C# 实现Eval(字符串表达式)的三种方法
一、背景
假如给定一个字符串表达式"-12 * ( - 2.2 + 7.7 ) - 44 * 2"
,让你计算结果,熟悉JavaScript的都知道有个Eval
函数可以直接进行计算,而C#中却没有这个函数,下面提供三种实现方式
二、代码
public class Class1
{
#region 方法一:利用CodeCom
[Obsolete]
System.CodeDom.Compiler.ICodeCompiler comp = new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler();
System.CodeDom.Compiler.CompilerParameters cp = new System.CodeDom.Compiler.CompilerParameters();
public object Eval_1(string Expression)
{
StringBuilder code = new StringBuilder();
code.Append("using System; \n");
code.Append("namespace ADOGuy { \n");
code.Append(" public class _Evaluator { \n");
code.Append(" public object __foo() ");
code.Append("{ ");
code.AppendFormat(" return ({0}); ", Expression);
code.Append("}\n");
code.Append("} }");
System.CodeDom.Compiler.CompilerResults cr = comp.CompileAssemblyFromSource(cp, code.ToString());
System.Reflection.Assembly a = cr.CompiledAssembly;
object _Compiled = a.CreateInstance("ADOGuy._Evaluator");
System.Reflection.MethodInfo mi = _Compiled.GetType().GetMethod("__foo");
return mi.Invoke(_Compiled, null);
}
#endregion
#region 方法二:对表达式分析
string Precede(string p, string q)
{
switch (p)
{
case "+":
case "-":
return ("*/(".IndexOf(q) != -1) ? "<" : ">";
case "*":
case "/":
return (q == "(") ? "<" : ">";
case "(":
return (q == ")") ? "=" : "<";
case ")":
return (q == "(") ? "?" : ">";
case "#":
return (q == "#") ? "=" : "<";
}
return "?";
}
Double Operate(Double a, char o, Double b)
{
switch (o)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
}
return 0;
}
public Object Eval_2(string Expression)
{
Stack nArr = new Stack(), oArr = new Stack();
int j = 0;
Double a = 0, b = 0;
string w = "";
char o;
MatchCollection arr = Regex.Matches(Expression.Replace(" ", "") + "#", @"(((?<=(^|\())-)?\d+(\.\d+)?|\D)");
oArr.Push('#');
w = Convert.ToString(arr[j++]);
while (!(w == "#" && Convert.ToString(oArr.Peek()) == "#"))
{
if ("+-*/()#".IndexOf(w) != -1)
{
switch (Precede(oArr.Peek().ToString(), w))
{
case "<":
oArr.Push(w);
w = Convert.ToString(arr[j++]);
break;
case "=":
oArr.Pop();
w = Convert.ToString(arr[j++]);
break;
case ">":
o = Convert.ToChar(oArr.Pop());
b = Convert.ToDouble(nArr.Pop());
a = Convert.ToDouble(nArr.Pop());
nArr.Push(Operate(a, o, b));
break;
default:
return "Error";
}
}
else
{
nArr.Push(w);
w = Convert.ToString(arr[j++]);
}
}
return nArr.Pop();
}
#endregion
#region 方法三:利用JScript的Eval
//需要引用Microsoft.JScript
[Obsolete]
readonly Microsoft.JScript.Vsa.VsaEngine ve = Microsoft.JScript.Vsa.VsaEngine.CreateEngine();
[Obsolete]
public object Eval_3(string Expression)
{
return Microsoft.JScript.Eval.JScriptEvaluate(Expression, ve);
}
#endregion
}
三、测试
static void Main(string[] args)
{
String strExpression = "-12 * ( - 2.2 + 7.7 ) - 44 * 2";
var obj = new Class1();
Console.WriteLine($"方法一(CodeCom法)计算结果:{obj.Eval_1(strExpression)}");
Console.WriteLine($"方法二(分析法)计算结果:{obj.Eval_2(strExpression)}");
Console.WriteLine($"方法三(JScript法)计算结果:{obj.Eval_3(strExpression)}");
Console.ReadLine();
}
运行结果:
方法一(CodeCom法)计算结果:-154
方法二(分析法)计算结果:-154
方法三(JScript法)计算结果:-154
C# 实现Eval(字符串表达式)的三种方法的更多相关文章
- [Python]实现字符串倒序的三种方法
a=" 1: print(a[::-1]) 2: b=list(a) b.reverse() print(''.join(b)) 3: c=len(a)-1 str_1=[] while(c ...
- python字符串连接的三种方法及其效率、适用场景详解
python字符串连接的方法,一般有以下三种:方法1:直接通过加号(+)操作符连接website=& 39;python& 39;+& 39;tab& 39;+& ...
- ibatis SQLmap mysql模糊查询字符串拼的三种方法
在通常情况下iBATIS的参数在sqlmap中使用#param#的形式,参数名以’#’包着,但当使用sql的LIKE语句时就发生了问题,在单引号中无法使用#param#这种形式,下面列举出了3种方法来 ...
- 【转】C语言中字符串输入的三种方法
在网上看到,讲的还算详细,转过来学习一下...... ======================================================================= 使 ...
- Shell中字符串分割的三种方法
问题:对于’1,2,3,4,5’这样的字符串输出采用,分隔开的1 2 3 4 5 特征:在字符串中没有空格 解决方法1: #!/bin/bash var=’1,2,3,4,5’ var=${var// ...
- 将字符串str1复制为字符串str2的三种方法
1.自己编写函数,将两个字符串进行复制 #include<iostream> using namespace std; int main(){ char str1[]="I lo ...
- 在Java中按字节获得字符串长度的三种方法
转载:http://www.blogjava.net/nokiaguy/archive/2010/04/11/317982.html 由于Java是基于Unicode编码的,因此,一个汉字的长度为1, ...
- python字符串连接的三种方法
1.+号连接 a="hello," b="world!" c=a+b print(c) 有一点需要注意的是,字符串类型是不可变的,所以每一次应用加号连接字符串都 ...
- C#中去除字符串空格的三种方法
static void Main() { //demo1 除去空格,提取出各个单词 string s = "a b c"; string[] word = s.Split(new ...
- c#封装DBHelper类 c# 图片加水印 (摘)C#生成随机数的三种方法 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象 c# 制作正方形图片 JavaScript 事件循环及异步原理(完全指北)
c#封装DBHelper类 public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> ...
随机推荐
- Vue——Ajax请求的基本使用
1.get方法发送Ajax请求 // 直接在 URL 上添加参数 ID=12345 axios.get('/user?ID=12345') .then(function (response) { co ...
- nginx001
本文档版权归属:陈雷雷,仅限学习交流 QQ:370460470 blog:www.chenleilei.net Nginx服务实践 简述Nginx(nginx.org) Nginx (engine x ...
- java检测当前CPU负载状态的方法
1.java检测当前CPU负载状态 在Java中,直接检测CPU负载状态并不像在操作系统命令行中那样简单,因为Java标准库并没有直接提供这样的功能.但是,我们可以通过几种方法间接地获取CPU负载信息 ...
- 代码审计——基础(JAVAEE)
JAVAEE 目录 JAVAEE 常见框架 Struct2(控制层) Hibernate(持久层(与数据库交互)(不用再写简单的sql语句,但是需要一些列复杂的配置文件))(全ORM模型) Sprin ...
- mac home目录下无法mkdir目录及文件的解决方法
主要参考以下几篇文章 https://www.cnblogs.com/zhangbao3/p/12600058.html https://www.v2ex.com/t/607387 https://w ...
- 剑指Offer-66.机器人的运动范围(C++/Java)
题目: 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子. 例如,当k为18时,机器人能够 ...
- ARC169
A 我们定义 \(dp_{dep}\) 为第 \(dep\) 层会对上一层产生多少的影响. 如果有一层的影响大于 \(0\),在足够次计算后那么肯定是正号.如果小于零那就一定是负号. 由于越久影响到的 ...
- Console LDAP 配置解密
之前通过短视频向大家介绍了 Console 如何集成 LDAP,但很多小伙伴反映按照视频里的配置后不成功.今天就结合小伙伴们反映的问题来跟大家详细介绍一下. Console LDAP 完整的配置参数如 ...
- win11 恢复Win10右键菜单的方法
1.Win+R运行CMD 2.输入:reg add HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocS ...
- shiro有哪些组件?
a.Authentication:身份认证/登录,验证用户是不是拥有相应的身份: b.Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限:即判断用户是否能做事情,常见的 ...