Aşağıdaki gibi geçerli bir matematik ifadesine sahip bir dizem varsa:
String s = "1 + 2 * 7";
NET'te bu ifadeyi benim için ayrıştırıp değerlendirecek ve sonucu döndürecek yerleşik bir kitaplık / işlev var mı? Bu durumda 15.
Aşağıdaki gibi geçerli bir matematik ifadesine sahip bir dizem varsa:
String s = "1 + 2 * 7";
NET'te bu ifadeyi benim için ayrıştırıp değerlendirecek ve sonucu döndürecek yerleşik bir kitaplık / işlev var mı? Bu durumda 15.
Yanıtlar:
Microsoft Komut Dosyası Kontrol Kitaplığı'na (COM) bir başvuru ekleyebilir ve bir ifadeyi değerlendirmek için bunun gibi bir kod kullanabilirsiniz. (JScript için de çalışır.)
Dim sc As New MSScriptControl.ScriptControl()
sc.Language = "VBScript"
Dim expression As String = "1 + 2 * 7"
Dim result As Double = sc.Eval(expression)
Düzenle - C # sürümü.
MSScriptControl.ScriptControl sc = new MSScriptControl.ScriptControl();
sc.Language = "VBScript";
string expression = "1 + 2 * 7";
object result = sc.Eval(expression);
MessageBox.Show(result.ToString());
Düzenle - ScriptControl bir COM nesnesidir. Projenin "Referans ekle" iletişim kutusunda "COM" sekmesini seçin ve "Microsoft Script Control 1.0" a gidin ve ok'u seçin.
Bu ünlü ve eski sorunun yerleşik olan DataTable.Compute"hile" yi akla getiren bir cevabı olmaması garip . İşte burada.
double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));
Aşağıdaki aritmetik operatörler ifadelerde desteklenir:
+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)
Daha Fazla Bilgi: DataColumn.ExpressionEn İfade Sözdizimi .
Silverlight üzerinde C # ile geliştirme yapan herkes için işte, Javascript motoruna seslenerek bir ifadenin değerlendirilmesine izin verdiğini keşfettiğim oldukça temiz bir numara:
double result = (double) HtmlPage.Window.Eval("15 + 35");
Http://ncalc.codeplex.com'u gördünüz mü ?
Genişletilebilir, hızlıdır (örneğin kendi önbelleğine sahiptir), EvaluateFunction / EvaluateParameter olaylarını işleyerek çalışma zamanında özel işlevler ve değişkenler sağlamanıza olanak tanır. Ayrıştırabileceği örnek ifadeler:
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());
Ayrıca, unicode ve birçok veri türünü yerel olarak işler. Dilbilgisini değiştirmek istiyorsanız, bir boynuz dosyası ile birlikte gelir. Yeni işlevleri yüklemek için MEF'i destekleyen bir çatal da vardır.
Aslında bir tür yerleşik bir tane var - XPath ad alanını kullanabilirsiniz! XPath gösterimi ile onaylamak için dizeyi yeniden biçimlendirmenizi gerektirse de. Basit ifadeleri işlemek için buna benzer bir yöntem kullandım:
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);
}
Başlangıçta muparser için c # sarmalayıcı kullandım . Bu çok hızlıydı. Bildiğim tek hızlı çözüm exprtk . Başka çözümler arıyorsanız, karşılaştırmayı kontrol edebilirsiniz .
Ancak .Net söz konusu olduğunda, çalışma zamanında kodu derlemek için yerleşik desteği kullanabilirsiniz. Buradaki fikir, örneğin değerlendirme formülünü değiştirebileceğiniz gömülü kaynak olarak bir "şablon" kaynak dosyasına sahip olmaktır. Daha sonra bu hazırlanmış sınıf kaynak kodunu derleyiciye iletirsiniz.
Temel bir şablon şöyle görünebilir:
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); }
...
İfadenin yerleştirileceği% formülüne dikkat edin.
Derlemek için CSharpCodeProvider sınıfını kullanın. Kaynağın tamamını buraya koymak istemiyorum. Ancak bu cevap yardımcı olabilir:
Bellek içi derlemeyi yükledikten sonra, sınıfınızın bir örneğini oluşturabilir ve EvalCode'u çağırabilirsiniz.
Roslyn'in mevcut olduğu başka bir seçenek daha:
Bunun için CodeAnalysis.CSharp.Scripting kütüphanesini kullanabilirsiniz.
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();
}
}
}
nuget paketleri:
<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" />
Son zamanlarda .NET ve JAVA için matematik ayrıştırıcı kitaplığı olan mXparser kullanıyordum. mXparser temel formüllerin yanı sıra çok süslü / karmaşık olanları (değişkenler, işlevler, operatörler, yineleme ve özyineleme dahil) destekler.
https://mxparser.codeplex.com/
Birkaç kullanım örneği:
Örnek 1:
Expression e = new Expression("1+2*7 + (sin(10) - 2)/3");
double v = e.calculate();
Örnek 2:
Argument x = new Argument("x = 5");
Expression e = new Expression("2*x+3", x);
double v = e.calculate();
Örnek 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();
Yakın zamanda bulundu - sözdizimini denemek (ve gelişmiş kullanım örneğini görmek) isterseniz, mXparser tarafından desteklenen Skaler Hesap Makinesi uygulamasını indirebilirsiniz.
Saygılarımla
Çok basit bir şeye ihtiyacınız varsa 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")
Ayrıca Jace'e ( https://github.com/pieterderycke/Jace ) bir göz atardım . Jace, tüm .NET çeşitlerini (.NET 4.x, Windows Phone, Windows Store, ...) destekleyen yüksek performanslı bir matematik ayrıştırıcı ve hesaplama motorudur. Jace ayrıca NuGet aracılığıyla da kullanılabilir: https://www.nuget.org/packages/Jace
Basit bir matematik ayrıştırıcısının oluşturulması oldukça kolaydır ve yalnızca birkaç satır kod gerektirir:
Bu esnek örneği ele alalım:
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);
Özyineleme ile arşivlenenler gibi bir yığın yığınını parantez içine alarak önceliği etkinleştirmek yeterli olacaktır. Parantezler arasında herhangi bir şey yeni bir yığına yerleştirilir. Son olarak, matematik işlemlerini lambdas tarafından okunabilir bir şekilde destekleyebilirsiniz.
100.5 + 300.5 - 100 * 10 / 100 = 30.1vs391
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
}
}
}
Birkaç yıl önce bir ifade ayrıştırıcısı uyguladım ve yakın zamanda GitHub ve Nuget: Albatross.Expression'da bunun bir sürümünü yayınladım . Aşağıdakiler gibi bir dizi ifadeyi değerlendirebilen bir ExecutionContext sınıfı içerir:
Ayrıca, yığın taşmasını önlemek için yararlı olan yerleşik dairesel referans denetimine sahiptir.
Benim yazarı olduğum Math-Expression-Evaluator kütüphanesini kullanabilirsiniz . Çok basit ifadeleri destekler gibi 2.5+5.9, 17.89-2.47+7.16, 5/2/2+1.5*3+4.58, parantez ile ifadeleri (((9-6/2)*2-4)/2-6-1)/(2+24/(2+4))değişkenlerle ve ifadelerin:
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});
Parametreleri adlandırılmış değişkenler olarak da iletebilirsiniz:
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);
Net Standard 2.0'ı destekler, böylece .Net Core ve .Net Full Framework projelerinden kullanılabilir ve herhangi bir harici bağımlılığı yoktur.
Flee Fast Lightweight İfade Değerlendiricisi
Dil referansı
Misal :
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)
Çıktı: 50
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));
}
}
}
Yüklemeyi unutma
<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />