要求:计算一个表达式的值
一般思路是对表达式进行解析,通过简单的语法分析利用数据结构有关技术进行计算求解。但是,如果仅仅是计算一个车结果,可以充分利用现有工具的便利性,绕过诸如堆栈,逆波兰式等等让人头疼的技巧而轻松实现。目前很多语言支持这种表达式的求值,我们所做的就是如何构造自己表达式,让用户可以比较容易的完成表达式的录入和检查即可。
根据要求,笔者采用了如下方法
第一步输入表达式,利用正则表达式,将表达式中的变量提取出来,其余的作为运算符处理。
第二步:将表达式保存到数据库中,使用时,用实际值替换变量值,从而生成一个标准的只包含常量和系统函数的表达式
第三步 使用系统提供计算函数对表达式进行计算,从而得到结果。
具体代码示意如下:
private void Lexer()
{
string formula = txt_Formula.Text;
string patternFunc = @"[A-Za-z]+[0-9]?\(";
string pattern = @"(?<Variable>[A-Za-z]+[0-9]?|@\bDevValue\b?|@\bDevInitial\b?)";
var simpleCheck = formula;
//1# replace the func with (), then use the old method to process. It is a little trick
string replacement = "(";
formula = Regex.Replace(formula, patternFunc, replacement);
dgv_Variable.Rows.Clear();
var varStr = "";
var i = 0;
// 将变量替换成具体数值,从而完成一个标椎的不含变量的表达式。
foreach (Match match in Regex.Matches(formula, pattern))
{
if (varStr.IndexOf(match.Value) < 0)
{
i++;
varStr += match.Value + "-";
txt_Notice.Text += match.Value + "\r\n";
int index = dgv_Variable.Rows.Add();
dgv_Variable.Rows[index].Cells["VOrder"].Value = i;
dgv_Variable.Rows[index].Cells["VName"].Value = match.Value;
if (match.Value.Equals(DisplayFormula.DevInitialVar)){
dgv_Variable.Rows[index].Cells["Value"].Value = m_IniVal;
}
}
simpleCheck = simpleCheck.Replace(match.Value, "1");
//Console.WriteLine(match.Value);
}
try
{
//user mysql syntax to check 2022-10-01
//1# form the mysql expression
FormulaEvaluate(simpleCheck);
txt_Notice.Text = "公式语法正确。\r\n" + txt_Notice.Text;
btn_OK.Enabled = true;
// The old method microsoft syntax check
//DataTable dt = new DataTable();
//dt.Compute(simpleCheck, "");
//txt_Notice.Text = "公式语法正确。\r\n" + txt_Notice.Text;
//btn_OK.Enabled = true;
// Generate the input filed
}
catch (Exception ex)
{
btn_OK.Enabled = false;
txt_Notice.Text =String.Format("公式语法有错,错误信息是{0}\r\n{1}", ex.Message ,txt_Notice.Text);
}
}
代码中用了一个小技巧,就是函数的支持。由于函数是固定的语法单位,可以把它当成计算符号处理,因此在分解变量时,笔者第一步将函数名全部替成空, 这样表原表达式相当于指包含了四则运算的基本符号,后面的提取变量的正则匹配就可以写的非常简单了。否则的话,可能要写的相当复杂,还有能支持递归的方法。(不知道正则表达式是否支持)。
formulaevaluate 函数中完成检查和计算,代码如下:
private static decimal FormulaEvaluate(string simpleCheck)
{
var sql = string.Format("select {0} ", simpleCheck);
var obj = My_SQLHelper.GetSingle(sql);
return Convert.ToDecimal(obj);
}
界面如下:
@开头的变量是系统里面的真正变化量,其余都是常量。
是记备忘。
maraSun BJFWDQ
11来了,你快了吗?