Занимаюсь математикой в ​​vb.net, как Eval в javascript - PullRequest
3 голосов
/ 21 сентября 2009

Есть ли способ проанализировать строку в vb.net (например, встроенные методы), которая может выполнять математику так же, как Eval? Например, 3+ (7 / 3.5) в виде строки вернет 2.

Я не прошу вас кодировать это для меня, я просто хочу знать, есть ли встроенный способ сделать это, если нет, я сам его кодирую.

Могу поспорить, что он не сможет самостоятельно разбирать такие вещи, как Sin (90), и я понимаю, что его необходимо заменить на Math.Sin (90).

Если есть встроенный метод, как вы его используете?

Ответы [ 6 ]

13 голосов
/ 21 сентября 2009

Существует ярлык для ограниченных (т. Е. Простых) математических выражений с использованием метода DataTable.Compute . Очевидно, что это не надежно (ограниченная функциональность) и кажется хакерским, чтобы неправильно использовать DataTable для этой цели, но я решил добавить к текущим ответам.

Пример:

var result = new DataTable().Compute("3+(7/3.5)", null); // 5

«Грех (90)» не будет работать с этим подходом. Обратитесь к странице DataColumn.Expression Property для получения списка поддерживаемых функций, в частности, в разделе «Агрегаты».

Использование пространства имен System.CodeDom является опцией.

Некоторые полезные ссылки:


РЕДАКТИРОВАТЬ: , чтобы ответить на ваш комментарий, вот подход, чтобы продемонстрировать замену тригонометрических функций их эквивалентными методами класса 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 для них. Если они представляют собой комбинацию элементов, этот простой подход не сработает. Я подозреваю, что вам постоянно нужно будет помогать решению, если оно становится слишком сложным с более неподдерживаемыми вызовами функций, и в этом случае подход CodeDom или другие могут быть более подходящими.

3 голосов
/ 14 сентября 2014

Вот способ оценить выражение, которое я не видел, упомянутое где-либо еще: используйте элемент управления 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
0 голосов
/ 07 августа 2010

Уже немного поздно, но здесь именно то, что вы хотели (убедитесь, что вы анализируете входные данные, чтобы убедиться, что в них нет выражения типа 'что-то + vbcrlf + exec "format 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
0 голосов
/ 21 сентября 2009

Один из способов - использовать пространство имен CodeDom для его компиляции и выполнения с использованием отражения. Может быть, не такой исполнитель, я не знаю.

0 голосов
/ 21 сентября 2009

Эта статья CodeProject может помочь:

Средство оценки выражений, написанное на VB.NET
http://www.codeproject.com/KB/vb/expression_evaluator.aspx

Существует также это:
http://www.dotnetspider.com/resources/2518-mathematical-expression-expression-evaluate-VB.aspx

0 голосов
/ 21 сентября 2009

Я не знаю о встроенном VB.net, но мы делаем такие вещи, связывая во время выполнения IronPython и передавая ему выражения. Это намного быстрее, чем при использовании отражения.

...