解析数学表达式

给定一个包含数学表达式的字符串,给定一组函数/命令并给定一组赋值变量,.NET是否提供了快速构建解析器的工具?

我想构建一个简单的解析器来分析表达式并将其分解为最简单的组件,例如:

d*(abs(ab)+sqrt(c))

  1. f = abs(ab)g = sqrt(c)
  2. e = f + g
  3. d*e

查看veparser 。 下面是一个示例代码,演示如何构建表达式求值程序(代码解析表达式并直接计算输出)。 可以修改此示例以存储评估树,而不是运行它。

 using System; using VeParser; public class MathEvaluator : CharParser { protected override Parser GetRootParser() { Func productFunc = (value1, value2) => value1 * value2; Func divideFunc = (value1, value2) => value1 / value2; Func sumFunc = (value1, value2) => value1 + value2; Func subtractFunc = (value1, value2) => value1 - value2; Func negativeFunc = value => -value; Func posititveFunc = value => value; var dot = token('.'); var op = token('('); var cp = token(')'); var sumOp = create(sumFunc, token('+')); var subtractOp = create(subtractFunc, token('-')); var positiveOp = create(posititveFunc, token('+')); var negativeOp = create(negativeFunc, token('-')); var productOp = create(productFunc, token('*')); var divideOp = create(divideFunc, token('/')); // Numbers var deciamlPlaceValue = 1M; var decimalDot = run(() => { deciamlPlaceValue = 1; }, dot); var digit = consume((n, d) => n * 10 + char.GetNumericValue(d), keep(Digit)); var decimalDigit = consume((n, d) => { deciamlPlaceValue = deciamlPlaceValue * 10; return (double)((decimal)n + ((decimal)char.GetNumericValue(d)) / deciamlPlaceValue); }, keep(Digit)); var number = any( /* float */ create(0, seq(zeroOrMore(digit), decimalDot, oneOrMore(decimalDigit))), /* int */ create(0, oneOrMore(digit)) ); var expression = createReference(); var simpleExpression = createReference(); // Unary var unaryOp = any(positiveOp, negativeOp); var unaryExpression = update(d => d.action(d.value), createNew(seq(set("action", unaryOp), set("value", expression)))); // Binary var binaryOp = any(sumOp, subtractOp, productOp, divideOp); var binaryExpressinoTree = update(x => x.value1, createNew( seq( set("value1", simpleExpression), zeroOrMore( update(d => { var r = base.CreateDynamicObject(); r.value1 = d.action(d.value1, d.value2); return r; }, seq( set("action", binaryOp), set("value2", simpleExpression)))) ))); var privilegedExpressoin = seq(op, expression, cp); setReference(simpleExpression, any(privilegedExpressoin, unaryExpression, number)); setReference(expression, any(binaryExpressinoTree, simpleExpression)); return seq(expression, endOfFile()); } public static object Eval(string expression) { MathEvaluator me = new MathEvaluator(); var result = me.Parse(expression.ToCharArray()); return result; } } 

您想构建解析器还是只提供解决方案?

无论哪种方式,请查看nCalc 。 如果您只需要解决它,请抓住二进制文件。 如果您需要查看它们如何解析表达式树,请获取源代码。

我听说过有关Grammatica解析器生成器的好东西。 ANTLR也被广泛使用(特别是在Java中)。

我假设您知道如何定义BNF语法并且过去已经了解或构建了解析器。

另一个Aproach

 class Program { static void Main(string[] args) { var a = 1; var b = 2; Console.WriteLine(FN_ParseSnippet($"{a} + {b} * 2")); Console.ReadKey(); } public static object FN_ParseSnippet(string snippet) { object ret = null; var usingList = new List(); usingList.Add("System"); usingList.Add("System.Collections.Generic"); usingList.Add("System.Text"); usingList.Add("Microsoft.CSharp"); //Create method CodeMemberMethod pMethod = new CodeMemberMethod(); pMethod.Name = "Execute"; pMethod.Attributes = MemberAttributes.Public; pMethod.ReturnType = new CodeTypeReference(typeof(object)); pMethod.Statements.Add(new CodeSnippetExpression(" return " + snippet)); //Create Class CodeTypeDeclaration pClass = new System.CodeDom.CodeTypeDeclaration("Compilator"); pClass.Attributes = MemberAttributes.Public; pClass.Members.Add(pMethod); //Create Namespace CodeNamespace pNamespace = new CodeNamespace("MyNamespace"); pNamespace.Types.Add(pClass); foreach (string sUsing in usingList) pNamespace.Imports.Add(new CodeNamespaceImport(sUsing)); //Create compile unit CodeCompileUnit pUnit = new CodeCompileUnit(); pUnit.Namespaces.Add(pNamespace); CompilerParameters param = new CompilerParameters(); param.GenerateInMemory = true; List pReferencedAssemblys = new List(); pReferencedAssemblys = Assembly.GetExecutingAssembly().GetReferencedAssemblies().ToList(); pReferencedAssemblys.Add(Assembly.GetExecutingAssembly().GetName()); pReferencedAssemblys.Add(Assembly.GetCallingAssembly().GetName()); foreach (AssemblyName asmName in pReferencedAssemblys) { Assembly asm = Assembly.Load(asmName); param.ReferencedAssemblies.Add(asm.Location); } //Compile CompilerResults pResults = (new CSharpCodeProvider()).CreateCompiler().CompileAssemblyFromDom(param, pUnit); if (pResults.Errors != null && pResults.Errors.Count > 0) { //foreach (CompilerError pError in pResults.Errors) // MessageBox.Show(pError.ToString()); } var instance = pResults.CompiledAssembly.CreateInstance("MyNamespace.Compilator"); ret = instance.GetType().InvokeMember("Execute", BindingFlags.InvokeMethod, null, instance, null); return ret; } }