一个简单的 C# 算术表达式 Eval 解析器 MathEvalor

作者 : admin 本文共2369个字,预计阅读时间需要6分钟 发布时间: 2024-06-5 共1人阅读

一、功能

该类实现了简单的算术表达式解析和计算,支持 ±*/%^ () 运算符。

二、先看效果

[TestMethod()]
public void EvalTest()
{
    Assert.AreEqual(MathEvalor.Eval<double>("-12 * ( - 2.2 + 7.7 ) - 44 * 2"), -154d);
    Assert.AreEqual(MathEvalor.Eval<double>("12 % (1+4)"), 2);
    Assert.AreEqual(MathEvalor.Eval<double>("3^(1+1)"), 9);
}

二、代码

代码逻辑很简单,用一个操作符堆栈和一个值堆栈实现。先依个解析表达式,遇到数字就丢到值堆栈,遇到操作符就判定,是该计算还是出入堆栈处理。等所有操作符都出栈计算完毕后,值堆栈里面的值就是表达式的值。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace App.CodeDoms
{
/// 
/// 简单的数学运算解析器。支持 +-*/%^运算。
/// 更复杂的支持常量、布尔值、函数的请查看 MathEval.NET 项目.
/// 
public class MathEvalor
{
/// 简单数学运算表达式计算
public static T Eval<T>(string expression) where T : struct
{
return (T)Eval(expression);
}
/// 简单数学运算表达式计算
public static object Eval(string expression)
{
expression = expression.Replace(" ", "") + "#";
Stack numbers = new Stack();
Stack operators = new Stack();
operators.Push('#');
int i = 0;
var words = Regex.Matches(expression, @"(((?<=(^|\())-)?\d+(\.\d+)?|\D)");
var word  = Convert.ToString(words[i++]);
while (word != "#" || operators.Peek().ToString() != "#")
{
if ("+-*/()%^#".Contains(word))
{
// 当前文本是操作符
switch (Judge(operators.Peek().ToString(), word))
{
case JudgeOp.Push:
operators.Push(word);
word = Convert.ToString(words[i++]);
break;
case JudgeOp.Pop:
operators.Pop();
word = Convert.ToString(words[i++]);
break;
case JudgeOp.Calc:
string o = Convert.ToString(operators.Pop());
double b = Convert.ToDouble(numbers.Pop());
double a = Convert.ToDouble(numbers.Pop());
numbers.Push(Operate(o, a, b));
break;
default:
return "Error";
}
}
else
{
// 当前文本是数字
numbers.Push(word);
word = Convert.ToString(words[i++]);
}
}
return numbers.Pop();
}
/// 判定结果
enum JudgeOp
{
Push,    // 操作符入栈
Pop,     // 操作符出栈
Calc,    // 计算
Error    // 错误
}
/// 判定操作是入栈、出栈、计算
/// 操作符
/// 后继文本
static JudgeOp Judge(string op, string next)
{
switch (op)
{
case "+":
case "-":
return "*/%^(".Contains(next) ? JudgeOp.Push : JudgeOp.Calc;
case "*":
case "/":
case "%":
case "^":
return (next == "(") ? JudgeOp.Push  : JudgeOp.Calc;
case "(":
return (next == ")") ? JudgeOp.Pop   : JudgeOp.Push;
case ")":
return (next == "(") ? JudgeOp.Error : JudgeOp.Calc;
case "#":
return (next == "#") ? JudgeOp.Pop   : JudgeOp.Push;
}
return JudgeOp.Error;
}
/// 二元操作
/// 二元操作符
static double Operate(string op, double a, double b)
{
switch (op)
{
case "+": return a + b;
case "-": return a - b;
case "*": return a * b;
case "/": return a / b;
case "%": return a % b;
case "^": return Math.Pow(a, b);
}
return 0;
}
}
}

三、扩展

更高级的表达式解析还可能包括以下内容:

  • 常量
  • 布尔值
  • 一元操作服、三元操作符
  • 函数:字符串函数、数学函数、日期时间、逻辑函数等
  • 类对象及属性
  • 扩展方法
  • Linq

可参考以下项目:

  • MathEval.NET
  • EvalExpression.NET
本站无任何商业行为
个人在线分享 » 一个简单的 C# 算术表达式 Eval 解析器 MathEvalor
E-->