Есть ли в .NET математический оценщик строк?
Если у меня есть строка с допустимым математическим выражением, например:
String s = "1 + 2 * 7";
Есть ли встроенная библиотека/функция в .NET, которая будет анализировать и оценивать это выражение для меня и возвращать результат? В этом случае 15.
Ответы
Ответ 1
Вы можете добавить ссылку на Microsoft Script Control Library (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)
Изменить - версия С#.
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" и выберите ok.
Ответ 2
Странно, что у этого знаменитого и старого вопроса нет ответа, который предлагает встроенный DataTable.Compute
- "трюк". Вот оно.
double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));
В выражениях поддерживаются следующие арифметические операторы:
+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)
Дополнительная информация: DataColumn.Expression
в синтаксисе выражений.
Ответ 3
Для любого, кто разрабатывает в С# в Silverlight здесь довольно аккуратный трюк, который я только что открыл, который позволяет оценивать выражение, вызывая механизм Javascript:
double result = (double) HtmlPage.Window.Eval("15 + 35");
Ответ 4
Вы видели 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 для загрузки новых функций.
Ответ 5
На самом деле есть встроенный встроенный - вы можете использовать пространство имен 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("<r/>"))
.CreateNavigator()
.Evaluate(xsltExpression);
}
Ответ 6
Сначала я использовал обертку С# для muparser. Это было очень быстро. Единственное более быстрое решение, которое я знаю, exprtk. Если вы ищете другие решения, вы можете проверить benchmark.
Но в случае .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. Я не хочу включать полный источник здесь. Но этот ответ может помочь:
После того, как вы загрузили сборку памяти, вы можете создать экземпляр своего класса и вызвать EvalCode.
Ответ 7
Недавно я использовал mXparser, который представляет собой библиотеку математического анализатора для .NET и JAVA. mXparser поддерживает основные формулы, а также очень фантастические/сложные (включая переменные, функции, операторы, итерацию и рекурсию).
https://mxparser.codeplex.com/
http://mathparser.org/
Несколько примеров использования:
Пример 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();
С наилучшими пожеланиями
Ответ 8
Если вам нужна очень простая вещь, вы можете использовать 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")
Ответ 9
Еще один вариант, который теперь доступен 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:
<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" />
Ответ 10
Я бы тоже посмотрел на Jace (https://github.com/pieterderycke/Jace). Jace - высокопроизводительный математический анализатор и вычислительный движок, поддерживающий все разновидности .NET(.NET 4.x, Windows Phone, Windows Store,...). Jace также доступен через NuGet: https://www.nuget.org/packages/Jace
Ответ 11
Простой математический анализатор достаточно прост в построении и требует всего несколько строк кода:
Возьмите этот гибкий пример:
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);
Чтобы включить приоритет с помощью брекетинга, будет достаточно стека стеков, например, архивируется рекурсией. Все, что находится между скобками, помещается в новый стек.
Наконец, вы можете поддерживать математические операции чистым читаемым способом лямбдами.
Ответ 12
Я реализовал парсер выражений несколько лет назад и опубликовал его версию в GitHub и Nuget: Albatross.Expression недавно. Он содержит класс ExecutionContext, который может оценивать набор выражений, таких как:
- MV = Цена * Кол-во;
- Цена = (Bid + Ask)/2;
- Bid =.6;
- Ask =.8;
Он также имеет встроенную циклическую контрольную проверку, которая полезна для предотвращения.
Ответ 13
Беги
Быстрая легкая оценка выражения
https://flee.codeplex.com
Справочник по языку
- Арифметические операции Пример: 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)
- ConditionalOperator Пример: если (a > 100 и b > 10, "как больше", "меньше" )
- Пример (список) InOperator: Если (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
Ответ 14
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
}
}
}