Есть ли в .NET математический оценщик строк?
Если у меня есть строка с допустимым математическим выражением, например:
String s = "1 + 2 * 7";
Есть ли встроенная библиотека / функция в .NET, которая будет анализировать и оценивать это выражение для меня и возвращать результат? В этом случае 15.
- Создание Qt5 с Visual Studio 2012 / Visual Studio 2013 и интеграция с IDE
- SetPixel слишком медленный. Есть ли более быстрый способ рисовать в bitmap?
- Почему члены статического classа должны быть объявлены как статические? Почему это не просто неявно?
- Почему многомерные массивы C # не реализуют IEnumerable ?
- В чем разница между .cpp-файлом и файлом .h?
- Зачем это нужно? = Null?
- Что такое функция батута?
- Пространства имен в C
- Оператор <и строгий слабый порядок
- Как я могу заставить элемент управления WebBrowser отображать современное содержимое?
- C - разделите строку на массив строк
- Как десериализовать данные JSON?
- Избегание сообщений об исключении из первой случайности, когда исключение безопасно обрабатывается
Вы можете добавить ссылку на библиотеку управления скриптами 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)
Изменить – версия на C #.
MSScriptControl.ScriptControl sc = new MSScriptControl.ScriptControl(); sc.Language = "VBScript"; string expression = "1 + 2 * 7"; object result = sc.Eval(expression); MessageBox.Show(result.ToString());
Изменить – ScriptControl – это COM-объект. В диалоговом окне «Добавить ссылку» проекта выберите вкладку «COM» и прокрутите вниз до «Microsoft Script Control 1.0» и выберите «ОК».
Странно, что у этого знаменитого и старого вопроса нет ответа, который предлагает встроенный DataTable.Compute
– «трюк». Вот.
double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));
В выражениях поддерживаются следующие арифметические операторы:
+ (addition) - (subtraction) * (multiplication) / (division) % (modulus)
Дополнительная информация: DataColumn.Expression
в синтаксисе выражений .
Для любого, кто развивается в C # в Silverlight, это довольно аккуратный трюк, который я только что обнаружил, который позволяет оценивать выражение, вызывая механизм Javascript:
double result = (double) HtmlPage.Window.Eval("15 + 35");
Вы видели http://ncalc.codeplex.com ?
Он расширяемый, быстрый (например, имеет собственный кеш) позволяет вам предоставлять пользовательские функции и переменные во время выполнения, обрабатывая события 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, " ${1} ") .Replace("/", " div ") .Replace("%", " mod ")); return (double)new XPathDocument (new StringReader(" ")) .CreateNavigator() .Evaluate(xsltExpression); }
Первоначально я использовал обертку c # для muparser . Это было очень быстро. Единственное более быстрое решение, которое я знаю, – exprtk . Если вы ищете другие решения, вы можете проверить контрольный показатель .
Но в случае .Net вы можете использовать встроенную поддержку для компиляции кода во время выполнения. Идея состоит в том, чтобы иметь исходный файл «шаблон», например, встроенный ресурс, где вы можете заменить формулу для оценки. Затем вы передаете этот подготовленный class-исходный код компилятору.
Основной шаблон может выглядеть так:
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); } ...
Обратите внимание на% -ную формулу%, в которую будет помещено выражение.
Для компиляции используйте class CSharpCodeProvider. Я не хочу включать полный источник здесь. Но этот ответ может помочь:
После того, как вы загрузите сборку памяти, вы можете создать экземпляр своего classа и вызвать 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();
С наилучшими пожеланиями
Еще один вариант теперь, когда Roslyn доступен:
Для этого вы можете использовать библиотеку CodeAnalysis.CSharp.Scripting.
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:
Если вам нужна очень простая вещь, вы можете использовать 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")
Я бы тоже посмотрел на Jace ( https://github.com/pieterderycke/Jace ). Jace – высокопроизводительный математический анализатор и вычислительный движок, поддерживающий все разновидности .NET (.NET 4.x, Windows Phone, Windows Store, …). Jace также доступен через NuGet: https://www.nuget.org/packages/Jace
Простой математический анализатор довольно прост в построении и требует всего несколько строк кода:
Возьмите этот гибкий пример:
class RPN { public static double Parse( Stack strStk ) { if (strStk == null || strStk.Count == 0 ) { return 0; } Stack numStk = new Stack (); double result = 0; Func 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 strStk = new Stack ( Regex.Split(str, @"([()*+\/-])", RegexOptions.Multiline).Reverse() ); RPN.Parse(strStk);
Чтобы включить приоритет путем брекетинга, достаточно стека стеков, например, архивируется рекурсией. Все, что находится между скобками, помещается в новый стек. Наконец, вы можете поддерживать математические операции чистым читаемым способом lambdaми.
Несколько лет назад я реализовал парсер выражений и недавно опубликовал его версию в GitHub и Nuget: Albatross.Expression . Он содержит class ExecutionContext, который может оценивать набор выражений, таких как:
- MV = Цена * Кол-во;
- Цена = (Bid + Ask) / 2;
- Bid = .6;
- Ask = .8;
Он также имеет встроенную циклическую контрольную проверку, которая полезна, чтобы избежать переполнения стека.
Быстрое облегчение оценки expressии
Языковой справочник
- Арифметические операции Пример: a * 2 + b ^ 2 – 100% 5
- Пример сравнения: 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 Example (List): If (100 in (100, 200, 300, -1), «in», «not in»)
- Перегруженные операторы по типам
Пример :
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, " ${1} ") .Replace("/", " div ") .Replace("%", " mod ")); // ReSharper disable PossibleNullReferenceException return (double)new XPathDocument (new StringReader(" ")) .CreateNavigator() .Evaluate(xsltExpression); // ReSharper restore PossibleNullReferenceException } } }