在JavaScript中像在Eval一样在VB.NET中做math运算
有没有什么办法来parsing一个string在vb.net(就像内置的方法),可以做像Eval的math可以? 例如,3+(7 / 3.5)作为string将返回2。
我不是要求你为我编码,我只是想知道是否有内置的方法来做到这一点,如果没有,我会自己编码。
我敢打赌,它不能像Sin(90)那样自行parsing,我知道这需要被Math.Sin(90)所取代。
如果有内置的方法,你如何使用它?
通过使用DataTable.Compute方法,有一个限制(即简单)mathexpression式的快捷方式 。 显然,这不是健壮的(有限的function),并且为此目的滥用DataTable感到ha but,但我想我会加上当前的答案。
例:
var result = new DataTable().Compute("3+(7/3.5)", null); // 5
“罪(90)”不适用于这种方法。 请参阅DataColumn.Expression属性页面 ,以获取支持的function列表,具体在“Aggregates”部分下。
使用System.CodeDom命名空间是一个选项。
一些有用的链接:
- CodeDom计算器
- 使用CodeDom评估mathexpression式
- 相关SO问题: 在.NET中是否有一个stringmath评估器?
编辑:为了解决您的评论,这里是一个方法来演示replace三angular函数与他们相当的math类的方法。
C#
string expression = "(Sin(0) + Cos(0)+Tan(0)) * 10"; string updatedExpression = Regex.Replace(expression, @"(?<func>Sin|Cos|Tan)\((?<arg>.*?)\)", match => match.Groups["func"].Value == "Sin" ? Math.Sin(Int32.Parse(match.Groups["arg"].Value)).ToString() : match.Groups["func"].Value == "Cos" ? Math.Cos(Int32.Parse(match.Groups["arg"].Value)).ToString() : Math.Tan(Int32.Parse(match.Groups["arg"].Value)).ToString() ); var result = new DataTable().Compute(updatedExpression, null); // 10
VB.NET
Dim expression As String = "(Sin(0) + Cos(0)+Tan(0)) * 10" Dim updatedExpression As String = Regex.Replace(expression, "(?<func>Sin|Cos|Tan)\((?<arg>.*?)\)", Function(match As Match) _ If(match.Groups("func").Value = "Sin", Math.Sin(Int32.Parse(match.Groups("arg").Value)).ToString(), _ If(match.Groups("func").Value = "Cos", Math.Cos(Int32.Parse(match.Groups("arg").Value)).ToString(), _ Math.Tan(Int32.Parse(match.Groups("arg").Value)).ToString())) _ ) Dim result = New DataTable().Compute(updatedExpression, Nothing)
但请注意,您需要知道“arg”组的内容。 我知道他们是整数,所以我使用了Int32.Parse。 如果他们是项目的组合,那么这种简单的方法将无法正常工作。 我怀疑如果有更多不支持的函数调用太复杂的话,你会不断需要创build解决scheme,在这种情况下,CodeDom方法或其他方法可能更适合。
这是一种评估expression式的方法,我没有在其他地方看到过:使用WebBrowser
控件和JavaScript的eval()
:
Option Strict On Imports System.Security.Permissions <PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _ <System.Runtime.InteropServices.ComVisibleAttribute(True)> Public Class Form1 Dim browser As New WebBrowser Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load browser.ObjectForScripting = Me 'browser.ScriptErrorsSuppressed = True browser.DocumentText = "<script>function evalIt(x) { return eval(x); }</script>" End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim result = browser.Document.InvokeScript("evalIt", New String() {"3+4*5"}) If result IsNot Nothing Then MessageBox.Show(result.ToString()) '23 End If End Sub End Class
这个CodeProject文章可能会诀窍:
一个用VB.NET编写的expression式求值器
http://www.codeproject.com/KB/vb/expression_evaluator.aspx
还有这个:
http://www.dotnetspider.com/resources/2518-mathematical-expression-expression-evaluate-VB.aspx
我不知道内置的VB.net,但我们通过在IronPython运行时连接并传递expression式来做这样的事情。 使用reflection速度更快。
一种方法是使用CodeDom命名空间来编译并使用reflection来执行它。 可能不是那个performance力,我不知道。
这有点晚了,但这正是你想要的(确保你parsinginput以确保没有像'something + vbcrlf + exec'格式c:''这样的语句):
用法:
MessageBox.Show(COR.Tools.EvalProvider.Eval("return 8-3*2").ToString())
类:
'Imports Microsoft.VisualBasic Imports System Namespace COR.Tools Public Class EvalProvider Public Shared Function Eval(ByVal vbCode As String) As Object Dim c As VBCodeProvider = New VBCodeProvider Dim icc As System.CodeDom.Compiler.ICodeCompiler = c.CreateCompiler() Dim cp As System.CodeDom.Compiler.CompilerParameters = New System.CodeDom.Compiler.CompilerParameters cp.ReferencedAssemblies.Add("System.dll") cp.ReferencedAssemblies.Add("System.xml.dll") cp.ReferencedAssemblies.Add("System.data.dll") ' Sample code for adding your own referenced assemblies 'cp.ReferencedAssemblies.Add("c:\yourProjectDir\bin\YourBaseClass.dll") 'cp.ReferencedAssemblies.Add("YourBaseclass.dll") cp.CompilerOptions = "/t:library" cp.GenerateInMemory = True Dim sb As System.Text.StringBuilder = New System.Text.StringBuilder("") sb.Append("Imports System" & vbCrLf) sb.Append("Imports System.Xml" & vbCrLf) sb.Append("Imports System.Data" & vbCrLf) sb.Append("Imports System.Data.SqlClient" & vbCrLf) sb.Append("Imports Microsoft.VisualBasic" & vbCrLf) sb.Append("Namespace MyEvalNamespace " & vbCrLf) sb.Append("Class MyEvalClass " & vbCrLf) sb.Append("public function EvalCode() as Object " & vbCrLf) 'sb.Append("YourNamespace.YourBaseClass thisObject = New YourNamespace.YourBaseClass()") sb.Append(vbCode & vbCrLf) sb.Append("End Function " & vbCrLf) sb.Append("End Class " & vbCrLf) sb.Append("End Namespace" & vbCrLf) Debug.WriteLine(sb.ToString()) ' look at this to debug your eval string Dim cr As System.CodeDom.Compiler.CompilerResults = icc.CompileAssemblyFromSource(cp, sb.ToString()) Dim a As System.Reflection.Assembly = cr.CompiledAssembly Dim o As Object Dim mi As System.Reflection.MethodInfo o = a.CreateInstance("MyEvalNamespace.MyEvalClass") Dim t As Type = o.GetType() mi = t.GetMethod("EvalCode") Dim s As Object s = mi.Invoke(o, Nothing) Return s End Function End Class ' EvalProvider End Namespace