операторы как строки

Мне нужно оценить математическое выражение, которое представлено мне как строка в C #. Пример noddy, но получает точку, через которую строка является выражением.

Мне нужна оценка, чтобы затем заполнить int.

В C # нет Eval (), как в других langugaes …

String myString = "3*4"; 

Редактировать:

Я на VS2008

Пробовал Microsoft.JScript. = Его устаревший метод (но по-прежнему соблюдает – предупреждение)

Однако dll Microsoft.JScript, на котором я работаю, работает

public object InvokeMember (имя строки, BindingFlags invokeAttr, связующее связующее, цель объекта, объект [] args);

Жалуется, что отсутствует “;” go figure …

EDIT 2

Решение – был codeDom один – он работал, поскольку нет проблемы безопасности – только я когда-либо буду запускать код. Большое спасибо за ответы …

И ссылка на новую книгу Дракона удивительна

ИЗМЕНИТЬ 3

Мэтт dataTable.Compute () также работает – еще лучше для безопасности. (отмечена проверка параметров)

Как я вижу это, у вас есть два варианта: использовать оценщик выражений или построить, скомпилировать и запустить код C # на лету.

Я бы пошел с библиотекой оценщиков выражений, так как вам не нужно беспокоиться о каких-либо проблемах безопасности. То есть, возможно, вы не сможете использовать генерацию кода в средах среднего доверия, таких как большинство общедоступных серверов хостинга.

Ниже приведен пример генерации кода для оценки выражений: http://www.vbforums.com/showthread.php?t=397264

Все остальные ответы могут быть излишними.

Если вам нужна простая арифметика, сделайте это.

  DataTable dummy = new DataTable(); Console.WriteLine(dummy.Compute("15 / 3",string.Empty)); 

EDIT: немного больше информации. Ознакомьтесь с документацией MSDN для свойства Expression classа System.Data.DataColumn . В «Синтаксисе выражений» описывается список команд, которые вы можете использовать в дополнение к арифметическим операторам. (например, IIF, LEN и т. д.). Спасибо всем, кто голосовал за мой первый ответ!

Я сделал это как личное упражнение на C # несколько недель назад.

Это довольно немного кода и плохо комментируется в местах. Но он работал с большим количеством тестовых примеров.

Наслаждайтесь!

 using System; using System.Collections.Generic; using System.Text.RegularExpressions; namespace StackOverflow { class Start { public static void Main(string[] args) { Evaluator ev; string variableValue, eq; Console.Write("Enter equation: "); eq = Console.ReadLine(); while (eq != "quit") { ev = new Evaluator(eq); foreach (Variable v in ev.Variables) { Console.Write(v.Name + " = "); variableValue = Console.ReadLine(); ev.SetVariable(v.Name, Convert.ToDecimal(variableValue)); } Console.WriteLine(ev.Evaluate()); Console.Write("Enter equation: "); eq = Console.ReadLine(); } } } class EvalNode { public virtual decimal Evaluate() { return decimal.Zero; } } class ValueNode : EvalNode { decimal value; public ValueNode(decimal v) { value = v; } public override decimal Evaluate() { return value; } public override string ToString() { return value.ToString(); } } class FunctionNode : EvalNode { EvalNode lhs = new ValueNode(decimal.Zero); EvalNode rhs = new ValueNode(decimal.Zero); string op = "+"; public string Op { get { return op; } set { op = value; } } internal EvalNode Rhs { get { return rhs; } set { rhs = value; } } internal EvalNode Lhs { get { return lhs; } set { lhs = value; } } public override decimal Evaluate() { decimal result = decimal.Zero; switch (op) { case "+": result = lhs.Evaluate() + rhs.Evaluate(); break; case "-": result = lhs.Evaluate() - rhs.Evaluate(); break; case "*": result = lhs.Evaluate() * rhs.Evaluate(); break; case "/": result = lhs.Evaluate() / rhs.Evaluate(); break; case "%": result = lhs.Evaluate() % rhs.Evaluate(); break; case "^": double x = Convert.ToDouble(lhs.Evaluate()); double y = Convert.ToDouble(rhs.Evaluate()); result = Convert.ToDecimal(Math.Pow(x, y)); break; case "!": result = Factorial(lhs.Evaluate()); break; } return result; } private decimal Factorial(decimal factor) { if (factor < 1) return 1; return factor * Factorial(factor - 1); } public override string ToString() { return "(" + lhs.ToString() + " " + op + " " + rhs.ToString() + ")"; } } public class Evaluator { string equation = ""; Dictionary variables = new Dictionary(); public string Equation { get { return equation; } set { equation = value; } } public Variable[] Variables { get { return new List(variables.Values).ToArray(); } } public void SetVariable(string name, decimal value) { if (variables.ContainsKey(name)) { Variable x = variables[name]; x.Value = value; variables[name] = x; } } public Evaluator(string equation) { this.equation = equation; SetVariables(); } public decimal Evaluate() { return Evaluate(equation, new List(variables.Values)); } public decimal Evaluate(string text) { decimal result = decimal.Zero; equation = text; EvalNode parsed; equation = equation.Replace(" ", ""); parsed = Parse(equation, "qx"); if (parsed != null) result = parsed.Evaluate(); return result; } public decimal Evaluate(string text, List variables) { foreach (Variable v in variables) { text = text.Replace(v.Name, v.Value.ToString()); } return Evaluate(text); } private static bool EquationHasVariables(string equation) { Regex letters = new Regex(@"[A-Za-z]"); return letters.IsMatch(equation); } private void SetVariables() { Regex letters = new Regex(@"([A-Za-z]+)"); Variable v; foreach (Match m in letters.Matches(equation, 0)) { v = new Variable(m.Groups[1].Value, decimal.Zero); if (!variables.ContainsKey(v.Name)) { variables.Add(v.Name, v); } } } #region Parse V2 private Dictionary parenthesesText = new Dictionary(); /* * 1. All the text in first-level parentheses is replaced with replaceText plus an index value. * (All nested parentheses are parsed in recursive calls) * 2. The simple function is parsed given the order of operations (reverse priority to * keep the order of operations correct when evaluating). * a. Addition (+), subtraction (-) -> left to right * b. Multiplication (*), division (/), modulo (%) -> left to right * c. Exponents (^) -> right to left * d. Factorials (!) -> left to right * e. No op (number, replaced parentheses) * 3. When an op is found, a two recursive calls are generated -- parsing the LHS and * parsing the RHS. * 4. An EvalNode representing the root node of the evaluations tree is returned. * * Ex. 3 + 5 (3 + 5) * 8 * + * * / \ / \ * 3 5 + 8 * / \ * 3 + 5 * 8 3 5 * + * / \ * 3 * * / \ * 5 8 */ ///  /// Parses the expression and returns the root node of a tree. ///  /// Equation to be parsed /// Text base that replaces text in parentheses ///  private EvalNode Parse(string eq, string replaceText) { int randomKeyIndex = 0; eq = eq.Replace(" ", ""); if (eq.Length == 0) { return new ValueNode(decimal.Zero); } int leftParentIndex = -1; int rightParentIndex = -1; SetIndexes(eq, ref leftParentIndex, ref rightParentIndex); //remove extraneous outer parentheses while (leftParentIndex == 0 && rightParentIndex == eq.Length - 1) { eq = eq.Substring(1, eq.Length - 2); SetIndexes(eq, ref leftParentIndex, ref rightParentIndex); } //Pull out all expressions in parentheses replaceText = GetNextReplaceText(replaceText, randomKeyIndex); while (leftParentIndex != -1 && rightParentIndex != -1) { //replace the string with a random set of characters, stored extracted text in dictionary keyed on the random set of chars string p = eq.Substring(leftParentIndex, rightParentIndex - leftParentIndex + 1); eq = eq.Replace(p, replaceText); parenthesesText.Add(replaceText, p); leftParentIndex = 0; rightParentIndex = 0; replaceText = replaceText.Remove(replaceText.LastIndexOf(randomKeyIndex.ToString())); randomKeyIndex++; replaceText = GetNextReplaceText(replaceText, randomKeyIndex); SetIndexes(eq, ref leftParentIndex, ref rightParentIndex); } /* * Be sure to implement these operators in the function node class */ char[] ops_order0 = new char[2] { '+', '-' }; char[] ops_order1 = new char[3] { '*', '/', '%' }; char[] ops_order2 = new char[1] { '^' }; char[] ops_order3 = new char[1] { '!' }; /* * In order to evaluate nodes LTR, the right-most node must be the root node * of the tree, which is why we find the last index of LTR ops. The reverse * is the case for RTL ops. */ int order0Index = eq.LastIndexOfAny(ops_order0); if (order0Index > -1) { return CreateFunctionNode(eq, order0Index, replaceText + "0"); } int order1Index = eq.LastIndexOfAny(ops_order1); if (order1Index > -1) { return CreateFunctionNode(eq, order1Index, replaceText + "0"); } int order2Index = eq.IndexOfAny(ops_order2); if (order2Index > -1) { return CreateFunctionNode(eq, order2Index, replaceText + "0"); } int order3Index = eq.LastIndexOfAny(ops_order3); if (order3Index > -1) { return CreateFunctionNode(eq, order3Index, replaceText + "0"); } //no operators... eq = eq.Replace("(", ""); eq = eq.Replace(")", ""); if (char.IsLetter(eq[0])) { return Parse(parenthesesText[eq], replaceText + "0"); } return new ValueNode(decimal.Parse(eq)); } private string GetNextReplaceText(string replaceText, int randomKeyIndex) { while (parenthesesText.ContainsKey(replaceText)) { replaceText = replaceText + randomKeyIndex.ToString(); } return replaceText; } private EvalNode CreateFunctionNode(string eq, int index, string randomKey) { FunctionNode func = new FunctionNode(); func.Op = eq[index].ToString(); func.Lhs = Parse(eq.Substring(0, index), randomKey); func.Rhs = Parse(eq.Substring(index + 1), randomKey); return func; } #endregion ///  /// Find the first set of parentheses ///  ///  ///  ///  private static void SetIndexes(string eq, ref int leftParentIndex, ref int rightParentIndex) { leftParentIndex = eq.IndexOf('('); rightParentIndex = eq.IndexOf(')'); int tempIndex = eq.IndexOf('(', leftParentIndex + 1); while (tempIndex != -1 && tempIndex < rightParentIndex) { rightParentIndex = eq.IndexOf(')', rightParentIndex + 1); tempIndex = eq.IndexOf('(', tempIndex + 1); } } } public struct Variable { public string Name; public decimal Value; public Variable(string n, decimal v) { Name = n; Value = v; } } } 

Вы можете использовать интерпретатор jscript. Отличная статья для этого: http://www.odetocode.com/Articles/80.aspx

Когда вы говорите «как на других языках», вы должны сказать «как в динамических языках».

Для динамических языков, таких как python, ruby ​​и многие интерпретируемые языки, функция Eval () является естественным элементом. На самом деле, возможно, даже довольно тривиально реализовать свои собственные.

Как бы то ни было. .Net – это статическая, сильно типизированная, скомпилированная платформа (по крайней мере, до тех пор, пока динамическая среда Runtime не получит больше поддержки). Это имеет естественные преимущества, такие как защита от кодового инъекций и проверка типа времени компиляции, которые трудно игнорировать. Но это означает, что функция Eval () не является такой хорошей подгонкой – она ​​хочет уметь заранее компилировать выражение. В такой платформе обычно существуют другие, более безопасные способы выполнения одной и той же задачи.

Отъезд Flee

MS имеет образец под названием Dynamic Query Library. Команда LINQ обеспечивает динамическое построение запросов LINQ, таких как: Dim query = Northwind.Products.Where (“CategoryID = 2”). Вы можете проверить, предлагает ли он рудиментарные математические возможности.

В интерпретируемом языке у вас может быть возможность оценить строку с помощью интерпретатора. В C # вам нужен парсер для языка, на котором написана строка (язык математических выражений). Это нетривиальное упражнение. Если вы хотите это сделать, используйте парсер рекурсивного спуска. Ранние главы «Книги дракона» («Составители: дизайн и т. Д.» Ахо, Сети и Ульман – 1-е изд., 1977 или 2-е изд., 2007) имеют хорошее объяснение того, что вам нужно делать.

Альтернативой может быть включение в ваш проект компонента, написанного на Perl, который должен быть доступен для .NET в настоящее время, и использовать perl для оценки.

Вам нужно будет получить доступ к значениям других переменных при вычислении выражения?

Может быть использован интерпретатор jscript , или вы можете написать собственный синтаксический анализатор, если выражение простое (остерегайтесь, оно становится очень сложным).

Я уверен, что в C # нет прямого метода «Eval (string)», поскольку он не интерпретируется.

Имейте в виду, что интерпретация кода подвержена инъекции кода, будьте особенно осторожны 🙂

После некоторого поиска в Google я вижу, что есть возможность создавать и компилировать код на лету с помощью CodeDom. (См. Учебник ).

Я лично не думаю, что этот подход является очень хорошей идеей, поскольку пользователь может ввести любой код, который ему нужен, но это может быть область для изучения (например, только проверка ввода и только разрешение чисел и простых математических операций) ,

Некоторые другие предложения:

  • Моно 2.0 (вышел сегодня) имеет метод eval.
  • Вы можете легко написать небольшой домен, определенный в boo.
  • Вы можете создать старый синтаксический анализатор EBNF для школьного рекурсивного спуска.

Я опубликовал источник для ультракомпактного (1 class, <10 KiB) Java Math Evaluator на моем веб-сайте. Должно быть тривиально переносить это на C #. Есть и другие, которые могут сделать больше, но это очень способно, и это крошечно .

  • Как читать данные из zip-файла без необходимости разархивировать весь файл
  • C: развернуть макрос с вставкой токена
  • Анонимный метод в вызове Invoke
  • Что такое безопасный тип в .net?
  • Ошибка при развертывании приложения ClickOnce. Ссылка в манифесте не соответствует идентификатору загруженной сборки
  • Как я могу написать общий class контейнера, который реализует данный интерфейс в C #?
  • Запись на указатель вне границ после malloc (), не вызывающая ошибки
  • Каковы наилучшие методы использования SmtpClient, SendAsync и Dispose в .NET 4.0
  • Можно ли определить тип параметра и тип возврата lambda?
  • Вывод Unicode на консоль Использование C ++ в Windows
  • Rx: Как я могу ответить немедленно и задушить последующие запросы
  • Interesting Posts

    Заменить специальные символы в XSLT

    jQuery: скрыть всплывающее окно, если щелчок обнаружен в другом месте

    Мне нужна моя команда sed -i для редактирования на месте для работы как с GNU sed, так и с BSD / OSX

    Какова полезность безгражданства в JSF?

    Подкомпоненты Dagger 2 и зависимости компонентов

    Аланофир-асинхронное завершениеHandler для запроса JSON

    Как выполнить необработанное обновление sql с динамическим привязкой в ​​рельсах

    Как заставить систему обнаруживать жесткие диски в качестве выделенного блока? (Например, / dev / sde)

    Что представляет собой современное состояние для текстового рендеринга в OpenGL с версии 4.1?

    Как создать общую учетную запись рабочей группы для учетной записи Windows 8 Online?

    ArrayIndexOutOfBoundsException при использовании iteratorа ArrayList

    JTable не отображается

    Открыть порт брандмауэра на CentOS 7

    Получение участка с разбивкой по областям в R

    Панель задач Windows 7, создайте всплывающие меню?

    Давайте будем гением компьютера.