Apakah ada evaluator matematika string di .NET?

95

Jika saya memiliki string dengan ekspresi matematika yang valid seperti:

String s = "1 + 2 * 7";

Apakah ada pustaka / fungsi bawaan di .NET yang akan mengurai dan mengevaluasi ekspresi itu untuk saya dan mengembalikan hasilnya? Dalam kasus ini 15.

Orang
sumber
2
Bukan yang built in. Tapi ada yang cukup komprehensif di sini .
Strelok
1
Anda dapat menggunakan ekspresi evaluator (fungsi
Evaluasi
Saya baru saja membuat solusi hanya kode untuk mengevaluasi ekspresi matematika di C #. Anda dapat melihat kodenya di blackbeltcoder.com/Articles/algorithms/ac-expression-evaluator .
Jonathan Wood
Perpustakaan ini sepertinya memiliki beberapa bug.
Philippe Lavoie

Jawaban:

53

Anda dapat menambahkan referensi ke Microsoft Script Control Library (COM) dan menggunakan kode seperti ini untuk mengevaluasi ekspresi. (Juga berfungsi untuk JScript.)

Dim sc As New MSScriptControl.ScriptControl()
sc.Language = "VBScript"
Dim expression As String = "1 + 2 * 7"
Dim result As Double = sc.Eval(expression)

Edit - versi C #.

MSScriptControl.ScriptControl sc = new MSScriptControl.ScriptControl();
sc.Language = "VBScript";
string expression = "1 + 2 * 7";
object result = sc.Eval(expression);            
MessageBox.Show(result.ToString());

Edit - ScriptControl adalah objek COM. Dalam dialog "Tambahkan referensi" dari proyek tersebut pilih tab "COM" dan gulir ke bawah ke "Microsoft Script Control 1.0" dan pilih ok.

pengguna21826
sumber
2
Meskipun ini ditandai sebagai jawaban, itu sudah 10 tahun yang lalu dan COM agak mati sekarang. Saya lebih suka jawaban DataTable.Compute di bawah ini.
dwilliss
64

Aneh bahwa pertanyaan terkenal dan lama ini tidak memiliki jawaban yang menyarankan DataTable.Compute"trik" bawaan. Ini dia.

double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));

Operator aritmatika berikut ini didukung dalam ekspresi:

+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)

Informasi lebih lanjut: DataColumn.Expressiondi Expression Syntax .

Tim Schmelter
sumber
ada jawaban dari ma81xx pada tanggal 15 November '11
tatigo
1
Anda benar, tapi itu tidak menggunakan metode Hitung.
Tim Schmelter
Contoh Anda memberi saya System.InvalidCastException tidak ditangani oleh kode pengguna HResult = -2147467262 Bagaimana cara memperbaikinya?
Yuliia Ashomok
Ini berfungsi untuk saya, apakah Anda sudah menggunakan kode sampel ini? Gunakan debugger dan periksa nilai hasil, jenisnya disebutkan.
Tim Schmelter
28

Untuk siapa pun yang mengembangkan C # di Silverlight, inilah trik yang cukup rapi yang baru saja saya temukan yang memungkinkan evaluasi ekspresi dengan memanggil mesin Javascript:

double result = (double) HtmlPage.Window.Eval("15 + 35");
Orang
sumber
Saya ingin tahu apakah Anda bisa merujuk ini di tempat lain. Mungkin tidak, tapi itu akan keren.
Joel Coehoorn
4
Saat ini mengevaluasi kode Javascript arbitrer, Anda mungkin ingin memastikan untuk membersihkan masukan Anda dan memastikan Anda tidak secara langsung menampilkan hasilnya. (Saya pikir ini akan menjadi cara yang baik untuk memperkenalkan XSS tanpa menyadarinya)
Dan Esparza
Coba masukkan angka dengan nol di depannya, hasilnya tidak dapat diandalkan. "054 + 6" memberi Anda 50 misalnya.
Terry
9
@djerry, itu karena bilangan dengan nol di depannya dianggap oktal oleh evaluator JS, dan oktal 054 sama dengan desimal 44.
André Leria
24

Pernahkah Anda melihat http://ncalc.codeplex.com ?

Ini dapat diperluas, cepat (misalnya memiliki cache sendiri) memungkinkan Anda untuk menyediakan fungsi dan varaibles kustom pada waktu proses dengan menangani peristiwa EvaluateFunction / EvaluateParameter. Contoh ekspresi yang dapat diurai:

Expression e = new Expression("Round(Pow(Pi, 2) + Pow([Pi2], 2) + X, 2)"); 

  e.Parameters["Pi2"] = new Expression("Pi * Pi"); 
  e.Parameters["X"] = 10; 

  e.EvaluateParameter += delegate(string name, ParameterArgs args) 
    { 
      if (name == "Pi") 
      args.Result = 3.14; 
    }; 

  Debug.Assert(117.07 == e.Evaluate()); 

Ini juga menangani unicode & banyak tipe data secara asli. Itu datang dengan file tanduk jika Anda ingin mengubah grammer. Ada juga garpu yang mendukung MEF untuk memuat fungsi baru.

GreyCloud
sumber
1
Perpustakaan yang bagus. Juga tersedia di NUGET
Paul Grimshaw
Inilah yang saya gunakan untuk pemecah persamaan diferensial saya yang mengambil input pengguna. Pertanyaannya ada di sini
kleineg
15

Sebenarnya ada semacam built-in - Anda dapat menggunakan namespace XPath! Meskipun itu mengharuskan Anda memformat ulang string untuk mengonfirmasi dengan notasi XPath. Saya telah menggunakan metode seperti ini untuk menangani ekspresi sederhana:

    public static double Evaluate(string expression)
    {
        var xsltExpression = 
            string.Format("number({0})", 
                new Regex(@"([\+\-\*])").Replace(expression, " ${1} ")
                                        .Replace("/", " div ")
                                        .Replace("%", " mod "));

        return (double)new XPathDocument
            (new StringReader("<r/>"))
                .CreateNavigator()
                .Evaluate(xsltExpression);
    }
cbp
sumber
12

Awalnya saya menggunakan c # wrapper untuk muparser . Ini sangat cepat. Satu-satunya solusi yang lebih cepat yang saya tahu adalah exprtk . Jika Anda mencari solusi lain, Anda dapat memeriksa benchmark .

Tetapi dalam kasus .Net Anda dapat menggunakan dukungan bawaan untuk mengkompilasi kode pada saat runtime. Idenya adalah untuk memiliki file sumber "template" seperti sumber daya yang disematkan di mana Anda dapat mengganti rumus untuk evaluasi. Kemudian Anda meneruskan kode sumber kelas yang telah disiapkan ini ke kompilator.

Template dasar bisa terlihat seperti ini:

public class CSCodeEvaler
{
    public double EvalCode()
    {
        return last = Convert.ToDouble(%formula%);
    }

    public double last = 0;
    public const double pi = Math.PI;
    public const double e = Math.E;
    public double sin(double value) { return Math.Sin(value); }
    public double cos(double value) { return Math.Cos(value); }
    public double tan(double value) { return Math.Tan(value); }
    ...

Perhatikan% formula% dimana ekspresi akan dimasukkan.

Untuk mengkompilasi gunakan kelas CSharpCodeProvider. Saya tidak ingin memasukkan secara lengkap sumbernya di sini. Tetapi jawaban ini mungkin membantu:

Setelah Anda memiliki perakitan memori dimuat Anda dapat membuat contoh kelas Anda dan memanggil EvalCode.

schoetbi
sumber
9

Namun pilihan lain sekarang setelah Roslyn tersedia:

Anda dapat menggunakan pustaka CodeAnalysis.CSharp.Scripting untuk ini.

using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;

namespace ExpressionParser
{
    class Program
    {
        static void Main(string[] args)
        {
            //Demonstrate evaluating C# code
            var result = CSharpScript.EvaluateAsync("System.DateTime.Now.AddDays(-1) > System.DateTime.Now").Result;
            Console.WriteLine(result.ToString());

            //Demonstrate evaluating simple expressions
            var result2 = CSharpScript.EvaluateAsync(" 5 * 7").Result;
            Console.WriteLine(result2);
            Console.ReadKey();
        }
    }
}

paket nuget:

<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Common" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.CSharp" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.CSharp.Scripting" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Scripting" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Scripting.Common" version="1.1.1" targetFramework="net461" />
Crowcoder
sumber
2
Ini harus menjadi jawabannya sekarang
sonofaforester
8

Baru-baru ini saya menggunakan mXparser, yang merupakan pustaka parser matematika untuk .NET dan JAVA. mXparser mendukung formula dasar serta formula yang sangat mewah / rumit (termasuk variabel, fungsi, operator, iterasi dan rekursi).

https://mxparser.codeplex.com/

https://mathparser.org/

Beberapa contoh penggunaan:

Contoh 1:

Expression e = new Expression("1+2*7 + (sin(10) - 2)/3");
double v = e.calculate();

Contoh 2:

Argument x = new Argument("x = 5");
Expression e = new Expression("2*x+3", x);
double v = e.calculate();

Contoh 3:

Function f = new Function("f(x,y) = sin(x) / cos(y)");
Expression e = new Expression("f(pi, 2*pi) - 2", f);
double v = e.calculate();

Ditemukan baru-baru - dalam kasus Anda ingin mencoba sintaks (dan melihat kasus penggunaan lanjutan) Anda dapat men-download Scalar Kalkulator aplikasi yang didukung oleh mXparser.

salam Hormat

Leroy Kegan
sumber
Ini adalah perpustakaan terbaik yang saya temukan. Namun, ini tidak mendukung tipe data selain angka! Saya perlu DateTime dan String .. apakah Anda tahu alternatif yang bagus?
Homam
@Homam Apakah Anda menemukan alternatif untuk operasi string
Ramakrishna Reddy
5

Jika Anda membutuhkan hal yang sangat sederhana, Anda dapat menggunakan DataTable:-)

Dim dt As New DataTable
dt.Columns.Add("A", GetType(Integer))
dt.Columns.Add("B", GetType(Integer))
dt.Columns.Add("C", GetType(Integer))
dt.Rows.Add(New Object() {12, 13, DBNull.Value})

Dim boolResult As Boolean = dt.Select("A>B-2").Length > 0

dt.Columns.Add("result", GetType(Integer), "A+B*2+ISNULL(C,0)")
Dim valResult As Object = dt.Rows(0)("result")
ma81xx
sumber
3

Pengurai matematika sederhana cukup mudah dibuat, dan hanya memerlukan beberapa baris kode:

Ambil contoh fleksibel ini:

class RPN
{
    public static double Parse( Stack<string> strStk )
    {
        if (strStk == null || strStk.Count == 0 )
        {
            return 0;
        }
        Stack<double> numStk = new Stack<double>();
        double result = 0;

        Func<double, double> op = null;
        while (strStk.Count > 0)
        {
            var s = strStk.Pop();
            switch (s)
            {
                case "+":
                    op = ( b ) => { return numStk.Pop() + b; };
                    break;
                case "-":
                    op = ( b ) => { return numStk.Pop() - b; };
                    break;
                case "*":
                    op = ( b ) => { return numStk.Pop() * b; };
                    break;
                case "/":
                    op = ( b ) => { return numStk.Pop() / b; };
                    break;

                default:
                    double.TryParse(s, NumberStyles.Any, out result);
                    if (numStk.Count > 0)
                    {
                        result = op(result);
                    }
                    numStk.Push(result);
                    break;
            }
        }
        return result;
    }
}

....
var str = " 100.5 + 300.5 - 100 * 10 / 100";    
str = Regex.Replace(str, @"\s", "", RegexOptions.Multiline);
Stack<string> strStk = new Stack<string>(
     Regex.Split(str, @"([()*+\/-])", RegexOptions.Multiline).Reverse()
);
RPN.Parse(strStk);

Untuk mengaktifkan presedensi dengan tanda kurung, tumpukan tumpukan sudah cukup, seperti diarsipkan dengan rekursi. Apa pun di antara tanda kurung diletakkan di tumpukan baru. Akhirnya Anda dapat mendukung operasi matematika dengan cara yang mudah dibaca oleh lambda.

Lorenz Lo Sauer
sumber
Anda mungkin ingin memverifikasi jawaban Anda. 100.5 + 300.5 - 100 * 10 / 100 = 30.1vs391
Tawani
1
namespace CalcExp
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            double res = Evaluate("4+5/2-1");

            Console.WriteLine(res);

        }

        public static double Evaluate(string expression)
        {
            var xsltExpression =
                string.Format("number({0})",
                    new Regex(@"([\+\-\*])").Replace(expression, " ${1} ")
                                            .Replace("/", " div ")
                                            .Replace("%", " mod "));

// ReSharper disable PossibleNullReferenceException
            return (double)new XPathDocument
                (new StringReader("<r/>"))
                    .CreateNavigator()
                    .Evaluate(xsltExpression);
// ReSharper restore PossibleNullReferenceException
        }

    }
}
pengguna2069333
sumber
3
-1: Gabungkan ini menjadi jawaban @cbp. Ada kebutuhan NOL untuk memiliki dua jawaban yang pada dasarnya identik ketika kita dapat memiliki satu jawaban yang fantastis.
Robert MacLean
1

Saya menerapkan pengurai ekspresi beberapa tahun yang lalu dan baru-baru ini menerbitkan versi di GitHub dan Nuget: Albatross.Expression . Ini berisi kelas ExecutionContext yang bisa mengevaluasi sekumpulan ekspresi seperti:

  • MV = Harga * Kuantitas;
  • Harga = (Bid + Ask) / 2;
  • Tawaran = 0,6;
  • Tanyakan = 0,8;

Ini juga memiliki pemeriksaan referensi melingkar yang berguna untuk menghindari tumpukan melimpah.

Rushui Guan
sumber
1

Anda dapat menggunakan library Math-Expression-Evaluator yang saya buat sendiri. Mendukung ekspresi sederhana seperti 2.5+5.9, 17.89-2.47+7.16, 5/2/2+1.5*3+4.58, ekspresi dengan tanda kurung (((9-6/2)*2-4)/2-6-1)/(2+24/(2+4))dan ekspresi dengan variabel:

var a = 6;
var b = 4.32m;
var c = 24.15m;
var engine = new ExpressionEvaluator();
engine.Evaluate("(((9-a/2)*2-b)/2-a-1)/(2+c/(2+4))", new { a, b, c});

Anda juga dapat mengirimkan parameter sebagai variabel bernama:

dynamic dynamicEngine = new ExpressionEvaluator();

var a = 6;
var b = 4.5m;
var c = 2.6m;

dynamicEngine.Evaluate("(c+b)*a", a: 6, b: 4.5, c: 2.6);

Ini mendukung .Net Standard 2.0 sehingga dapat digunakan dari .Net Core serta proyek .Net Full Framework dan tidak memiliki dependensi eksternal.

Giorgi
sumber
0

Penilai Ekspresi Cepat Ringan

https://flee.codeplex.com

Referensi Bahasa

  • Contoh Operator Aritmatika: a * 2 + b ^ 2 - 100% 5
  • Contoh ComparisonOperators: a <> 100
  • Contoh AndOrXorNotOperators (logika): a> 100 Dan Bukan b = 100
  • Contoh ShiftOperators: 100 >> 2
  • Contoh Penggabungan: "abc" + "def"
  • Contoh Pengindeksan: arr [i + 1] + 100
  • Literals
  • Contoh Casting: 100+ cast (obj, int)
  • Contoh ConditionalOperator: If (a> 100 dan b> 10, "keduanya lebih besar", "lebih sedikit")
  • Contoh InOperator (List): If (100 in (100, 200, 300, -1), "in", "not in")
  • Operator Overloaded Pada Jenis

Contoh:

Imports Ciloci.Flee
Imports Ciloci.Flee.CalcEngine
Imports System.Math

    Dim ec As New Ciloci.Flee.ExpressionContext
    Dim ex As IDynamicExpression
    ec.Imports.AddType(GetType(Math))

    ec.Variables("a") = 10            
    ec.Variables("b") = 40               
    ex = ec.CompileDynamic("a+b")

    Dim evalData    
    evalData = ex.Evaluate()
    Console.WriteLine(evalData)

Outputnya: 50

ISCI
sumber
0

MathNet. Simbolis

using System;
using static MathNet.Symbolics.SymbolicExpression;
using static System.Console;
using static System.Numerics.Complex;
using Complex = System.Numerics.Complex;

namespace MathEvaluator
{
    class Program
    {
        static readonly Complex i = ImaginaryOne;

        static void Main(string[] args)
        {
            var z = Variable("z");
            Func<Complex, Complex> f = Parse("z * z").CompileComplex(nameof(z));
            Complex c = 1 / 2 - i / 3;
            WriteLine(f(c));


            var x = Variable("x");
            Func<double, double> g = Parse("x * x + 5 * x + 6").Compile(nameof(x));
            double a = 1 / 3.0;
            WriteLine(g(a));
        }
    }
}

Jangan lupa memuat

<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />
Programmer Berorientasi Uang
sumber