Есть ли строковый математический вычислитель in.NET?
Если у меня есть строка с допустимым математическим выражением, например:
String s = "1 + 2 * 7";
есть ли встроенная библиотека / функция в .NET, которая будет анализировать и оценивать это выражение для меня и возвращать результат? В данном случае 15.
14 ответов:
вы можете добавить ссылку на библиотеку управления сценариями Microsoft (COM) и использовать такой код для вычисления выражения. (Также работает для 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 - 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 является COM-объектом. В диалоговом окне" Добавить ссылку "проекта выберите вкладку" COM "и прокрутите вниз до" Microsoft Script Control 1.0 " и выберите ok.
странно, что этот знаменитый и старый вопрос не имеет ответа, что наталкивает на строение
DataTable.Compute
-"трюк". Вот оно.double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));
в выражениях поддерживаются следующие арифметические операторы:
+ (addition) - (subtraction) * (multiplication) / (division) % (modulus)
дополнительная информация:
DataColumn.Expression
at Синтаксис Выражения.
для любого, кто развивается в C# на Silverlight вот довольно аккуратный трюк, который я только что обнаружил, что позволяет оценивать выражение, вызывая движок Javascript:
double result = (double) HtmlPage.Window.Eval("15 + 35");
вы видели http://ncalc.codeplex.com?
это расширяемый, быстрый (например, имеет свой собственный кэш) позволяет предоставлять пользовательские функции и varaibles во время выполнения путем обработки EvaluateFunction/EvaluateParameter событий. Примеры выражений, которые он может разобрать:
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());
Он также обрабатывает unicode и многие типы данных изначально. Он поставляется с файлом antler, если вы хотите изменить Граммер. Существует также вилка, которая поддерживает MEF для загрузки новых функций.
на самом деле есть своего рода встроенный в один - вы можете использовать пространство имен XPath! Хотя это требует, чтобы вы переформатировали строку для подтверждения с помощью нотации XPath. Я использовал такой метод для обработки простых выражений:
public static double Evaluate(string expression) { var xsltExpression = string.Format("number({0})", new Regex(@"([\+\-\*])").Replace(expression, " ") .Replace("/", " div ") .Replace("%", " mod ")); return (double)new XPathDocument (new StringReader("<r/>")) .CreateNavigator() .Evaluate(xsltExpression); }
изначально я использовал оболочку c# для muparser. Это было очень быстро. Единственное быстрое решение, которое я знаю, это exprtk. Если вы ищете другие решения, вы можете проверить ориентир.
но в случае .Net вы можете использовать встроенную поддержку для компиляции кода во время выполнения. Идея состоит в том, чтобы иметь исходный файл "шаблона" в качестве, например, встроенного ресурса, где вы можете заменить формулу для оценки. Затем вы передаете это подготовленным класс-исходный код для компилятора.
базовый шаблон может выглядеть так:
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); } ...
обратите внимание на формулу%%, в которую будет вставлено выражение.
для компиляции используйте класс CSharpCodeProvider. Я не хочу помещать здесь полный источник. Но ответ может помочь:
после загрузки сборки in memory вы можете создать экземпляр своего класса и вызвать EvalCode.
недавно я использовал mXparser, который является библиотекой математического парсера для .NET и JAVA. mXparser поддерживает базовые формулы, а также очень сложные / сложные (включая переменные, функции, операторы, итерации и рекурсии).
https://mxparser.codeplex.com/
несколько примеров использования:
Пример 1:
Expression e = new Expression("1+2*7 + (sin(10) - 2)/3"); double v = e.calculate();
Пример 2:
Argument x = new Argument("x = 5"); Expression e = new Expression("2*x+3", x); double v = e.calculate();
пример 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();
С наилучшими пожеланиями
Если вам нужна очень простая вещь, которую вы можете использовать
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")
еще один вариант Теперь, когда Рослин доступен:
Вы можете использовать CodeAnalysis.CSharp.Библиотека сценариев для этого.
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:
<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" />
Я бы также посмотрел на Джейса (https://github.com/pieterderycke/Jace). Jace-это высокопроизводительный математический парсер и вычислительный движок, который поддерживает все варианты .NET (.NET 4.x, Windows Phone, Windows Store, ...). Джейс также доступен через NuGet: https://www.nuget.org/packages/Jace
простой математический парсер довольно легко построить, и требует всего несколько строк кода:
возьмите этот гибкий пример:
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);
чтобы включить приоритет путем брекетинга стека стеков будет достаточно, например, архивируется рекурсией. Все, что находится между скобками, помещается в новый стек. Наконец, вы можете поддерживать математические операции в чистом читаемом виде с помощью лямбд.
я реализовал парсер выражений несколько лет назад и опубликовал версию его в GitHub и Nuget: Альбатрос.Выражение недавно. Он содержит класс ExecutionContext, который может вычислять набор выражений, таких как:
- MV = цена * кол-во;
- Price = (Bid + Ask)/2;
- Bid = .6;
- Ask = .8;
Он также имеет встроенную круговую проверку ссылок, которую полезно избегать переполнение стека.
бежать Быстрый Облегченный Оценщик Выражений
Ссылка На Язык
- пример арифметических операторов: a*2 + b ^ 2-100 % 5
- ComparisonOperators пример: a 100
- пример AndOrXorNotOperators (логический): a > 100, а не b = 100
- ShiftOperators Пример: 100 > > 2
- пример конкатенации: "abc" + "def"
- пример индексирования: arr[i + 1] + 100
- литералы
- пример литья: 100 + cast (obj, int)
- пример условного оператора: Если (a > 100 и b > 10, "оба больше", "меньше")
- пример InOperator (список): If (100 in (100, 200, 300, -1), "в", "не в")
- Перегруженные Операторы По Типам
пример :
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)
выход: 50
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, " ") .Replace("/", " div ") .Replace("%", " mod ")); // ReSharper disable PossibleNullReferenceException return (double)new XPathDocument (new StringReader("<r/>")) .CreateNavigator() .Evaluate(xsltExpression); // ReSharper restore PossibleNullReferenceException } } }