Оценивая строку «3 * (4 + 2)», получим int 18 [дубликат]

    

На этот вопрос уже есть ответ здесь:

    

Есть ли функция .NET Framework, которая может вычислять числовое выражение, содержащееся в строке, и возвращать результат? F.e:.

string mystring = "3*(2+4)";
int result = EvaluateExpression(mystring);
Console.Writeln(result); // Outputs 18

Существует ли стандартная каркасная функция, которую вы можете заменить моим методом EvaluateExpression на?

90 голосов | спросил sindre j 2 TueEurope/Moscow2008-12-02T14:57:15+03:00Europe/Moscow12bEurope/MoscowTue, 02 Dec 2008 14:57:15 +0300 2008, 14:57:15

13 ответов


0

Да, вы можете позволить компилятору C # оценивать его во время выполнения.

См .: CSharpCorner

ответил arul 2 TueEurope/Moscow2008-12-02T15:01:21+03:00Europe/Moscow12bEurope/MoscowTue, 02 Dec 2008 15:01:21 +0300 2008, 15:01:21
0

Если вы хотите оценить строковое выражение, используйте приведенный ниже фрагмент кода.

using System.Data;

DataTable dt = new DataTable();
var v = dt.Compute("3 * (2+4)","");
ответил Ramesh Sambari 14 J0000006Europe/Moscow 2012, 13:03:13
0

Использование компилятора влечет за собой утечки памяти, так как сгенерированные сборки загружаются и никогда не освобождаются. Это также менее производительно, чем использование реального интерпретатора выражений. Для этой цели вы можете использовать Ncalc , который является платформой с открытым исходным кодом с этим исключительно намерением. Вы также можете определить свои собственные переменные и пользовательские функции, если уже включенных уже недостаточно.

Пример:

Expression e = new Expression("2 + 3 * 5");
Debug.Assert(17 == e.Evaluate());
ответил Sébastien Ros - MSFT 14 +04002009-10-14T11:47:01+04:00312009bEurope/MoscowWed, 14 Oct 2009 11:47:01 +0400 2009, 11:47:01
0

Попробуйте это:

static double Evaluate(string expression) {
  var loDataTable = new DataTable();
  var loDataColumn = new DataColumn("Eval", typeof (double), expression);
  loDataTable.Columns.Add(loDataColumn);
  loDataTable.Rows.Add(0);
  return (double) (loDataTable.Rows[0]["Eval"]);
}
ответил Petar Repac 13 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSun, 13 Sep 2009 15:13:41 +0400 2009, 15:13:41
0

Вы можете посмотреть "XpathNavigator.Evaluate". Я использовал это для обработки математических выражений для моего GridView, и он отлично работает для меня.

Вот код, который я использовал для моей программы:

public static double Evaluate(string expression)
{
    return (double)new System.Xml.XPath.XPathDocument
    (new StringReader("<r/>")).CreateNavigator().Evaluate
    (string.Format("number({0})", new
    System.Text.RegularExpressions.Regex(@"([\+\-\*])")
    .Replace(expression, " ${1} ")
    .Replace("/", " div ")
    .Replace("%", " mod ")));
}
ответил Olav Botterli 13 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSun, 13 Sep 2009 14:47:48 +0400 2009, 14:47:48
0

Это простой анализатор выражений, использующий стеки

public class MathEvaluator
{
    public static void Run()
    {
        Eval("(1+2)");
        Eval("5*4/2");
        Eval("((3+5)-6)");
    }

    public static void Eval(string input)
    {
        var ans = Evaluate(input);
        Console.WriteLine(input + " = " + ans);
    }

    public static double Evaluate(String input)
    {
        String expr = "(" + input + ")";
        Stack<String> ops = new Stack<String>();
        Stack<Double> vals = new Stack<Double>();

        for (int i = 0; i < expr.Length; i++)
        {
            String s = expr.Substring(i, 1);
            if (s.Equals("(")){}
            else if (s.Equals("+")) ops.Push(s);
            else if (s.Equals("-")) ops.Push(s);
            else if (s.Equals("*")) ops.Push(s);
            else if (s.Equals("/")) ops.Push(s);
            else if (s.Equals("sqrt")) ops.Push(s);
            else if (s.Equals(")"))
            {
                int count = ops.Count;
                while (count > 0)
                {
                    String op = ops.Pop();
                    double v = vals.Pop();
                    if (op.Equals("+")) v = vals.Pop() + v;
                    else if (op.Equals("-")) v = vals.Pop() - v;
                    else if (op.Equals("*")) v = vals.Pop()*v;
                    else if (op.Equals("/")) v = vals.Pop()/v;
                    else if (op.Equals("sqrt")) v = Math.Sqrt(v);
                    vals.Push(v);

                    count--;
                }
            }
            else vals.Push(Double.Parse(s));
        }
        return vals.Pop();
    }
}
ответил Tawani 16 22010vEurope/Moscow11bEurope/MoscowTue, 16 Nov 2010 17:54:20 +0300 2010, 17:54:20
0

Это выполнение справа налево, поэтому нужно использовать правильный паратез для выполнения выражения

    // 2+(100/5)+10 = 32
    //((2.5+10)/5)+2.5 = 5
    // (2.5+10)/5+2.5 = 1.6666
    public static double Evaluate(String expr)
    {

        Stack<String> stack = new Stack<String>();

        string value = "";
        for (int i = 0; i < expr.Length; i++)
        {
            String s = expr.Substring(i, 1);
            char chr = s.ToCharArray()[0];

            if (!char.IsDigit(chr) && chr != '.' && value != "")
            {
                stack.Push(value);
                value = "";
            }

            if (s.Equals("(")) {

                string innerExp = "";
                i++; //Fetch Next Character
                int bracketCount=0;
                for (; i < expr.Length; i++)
                {
                    s = expr.Substring(i, 1);

                    if (s.Equals("("))
                        bracketCount++;

                    if (s.Equals(")"))
                        if (bracketCount == 0)
                            break;
                        else
                            bracketCount--;


                    innerExp += s;
                }

                stack.Push(Evaluate(innerExp).ToString());

            }
            else if (s.Equals("+")) stack.Push(s);
            else if (s.Equals("-")) stack.Push(s);
            else if (s.Equals("*")) stack.Push(s);
            else if (s.Equals("/")) stack.Push(s);
            else if (s.Equals("sqrt")) stack.Push(s);
            else if (s.Equals(")"))
            {
            }
            else if (char.IsDigit(chr) || chr == '.')
            {
                value += s;

                if (value.Split('.').Length > 2)
                    throw new Exception("Invalid decimal.");

                if (i == (expr.Length - 1))
                    stack.Push(value);

            }
            else
                throw new Exception("Invalid character.");

        }


        double result = 0;
        while (stack.Count >= 3)
        {

            double right = Convert.ToDouble(stack.Pop());
            string op = stack.Pop();
            double left = Convert.ToDouble(stack.Pop());

            if (op == "+") result = left + right;
            else if (op == "+") result = left + right;
            else if (op == "-") result = left - right;
            else if (op == "*") result = left * right;
            else if (op == "/") result = left / right;

            stack.Push(result.ToString());
        }


        return Convert.ToDouble(stack.Pop());
    }
ответил Rajesh Jinaga 14 MarpmMon, 14 Mar 2011 15:18:48 +03002011-03-14T15:18:48+03:0003 2011, 15:18:48
0

Вы можете довольно легко запустить это через CSharpCodeProvider с подходящим пухом, обертывающим его (тип и метод, в основном) Точно так же вы можете пройти через VB и т. Д. - или JavaScript, как предлагает другой ответ. На данный момент я не знаю ничего другого, встроенного в структуру.

Я ожидаю, что .NET 4.0 с его поддержкой динамических языков вполне может иметь лучшие возможности в этом направлении.

ответил Jon Skeet 2 TueEurope/Moscow2008-12-02T15:00:48+03:00Europe/Moscow12bEurope/MoscowTue, 02 Dec 2008 15:00:48 +0300 2008, 15:00:48
0

Недавно мне нужно было сделать это для проекта, и в итоге я использовал IronPython , чтобы сделать это. Вы можете объявить экземпляр движка, а затем передать любое допустимое выражение Python и получить результат. Если вы просто делаете простые математические выражения, то этого будет достаточно. Мой код в итоге выглядел примерно так:

IronPython.Hosting.PythonEngine pythonEngine = new IronPython.Hosting.PythonEngine();
string expression = "3*(2+4)";
double result = pythonEngine.EvaluateAs<double>(expression);

Возможно, вы не захотите создавать движок для каждого выражения. Вам также нужна ссылка на IronPython.dll

ответил Beardo 2 TueEurope/Moscow2008-12-02T18:44:26+03:00Europe/Moscow12bEurope/MoscowTue, 02 Dec 2008 18:44:26 +0300 2008, 18:44:26
0

РЕДАКТИРОВАТЬ: Понимаю, что я действительно должен отдельно выделить сложение и вычитание, чтобы сделать его немного более совместимым с BODMAS.

Большое спасибо Раджешу Джинаге за его подход, основанный на стеке. Я нашел это действительно полезным для моих нужд. Следующий код представляет собой небольшую модификацию метода Раджеша, который сначала обрабатывает деления, затем умножения, а затем заканчивает сложением и вычитанием. Это также позволит использовать логические выражения в выражениях, где true обрабатывается как 1, а false 0. что позволяет использовать логическую логику в выражениях.

public static double Evaluate(string expr)
    {
        expr = expr.ToLower();
        expr = expr.Replace(" ", "");
        expr = expr.Replace("true", "1");
        expr = expr.Replace("false", "0");

        Stack<String> stack = new Stack<String>();

        string value = "";
        for (int i = 0; i < expr.Length; i++)
        {
            String s = expr.Substring(i, 1);
            // pick up any doublelogical operators first.
            if (i < expr.Length - 1)
            {
                String op = expr.Substring(i, 2);
                if (op == "<=" || op == ">=" || op == "==")
                {
                    stack.Push(value);
                    value = "";
                    stack.Push(op);
                    i++;
                    continue;
                }
            }

            char chr = s.ToCharArray()[0];

            if (!char.IsDigit(chr) && chr != '.' && value != "")
            {
                stack.Push(value);
                value = "";
            }
            if (s.Equals("("))
            {
                string innerExp = "";
                i++; //Fetch Next Character
                int bracketCount = 0;
                for (; i < expr.Length; i++)
                {
                    s = expr.Substring(i, 1);

                    if (s.Equals("(")) bracketCount++;

                    if (s.Equals(")"))
                    {
                        if (bracketCount == 0) break;
                        bracketCount--;
                    }
                    innerExp += s;
                }
                stack.Push(Evaluate(innerExp).ToString());
            }
            else if (s.Equals("+") ||
                     s.Equals("-") ||
                     s.Equals("*") ||
                     s.Equals("/") ||
                     s.Equals("<") ||
                     s.Equals(">"))
            {
                stack.Push(s);
            }
            else if (char.IsDigit(chr) || chr == '.')
            {
                value += s;

                if (value.Split('.').Length > 2)
                    throw new Exception("Invalid decimal.");

                if (i == (expr.Length - 1))
                    stack.Push(value);

            }
            else
            {
                throw new Exception("Invalid character.");
            }

        }
        double result = 0;
        List<String> list = stack.ToList<String>();
        for (int i = list.Count - 2; i >= 0; i--)
        {
            if (list[i] == "/")
            {
                list[i] = (Convert.ToDouble(list[i - 1]) / Convert.ToDouble(list[i + 1])).ToString();
                list.RemoveAt(i + 1);
                list.RemoveAt(i - 1);
                i -= 2;
            }
        }

        for (int i = list.Count - 2; i >= 0; i--)
        {
            if (list[i] == "*")
            {
                list[i] = (Convert.ToDouble(list[i - 1]) * Convert.ToDouble(list[i + 1])).ToString();
                list.RemoveAt(i + 1);
                list.RemoveAt(i - 1);
                i -= 2;
            }
        }
        for (int i = list.Count - 2; i >= 0; i--)
        {
            if (list[i] == "+")
            {
                list[i] = (Convert.ToDouble(list[i - 1]) + Convert.ToDouble(list[i + 1])).ToString();
                list.RemoveAt(i + 1);
                list.RemoveAt(i - 1);
                i -= 2;
            }
        }
        for (int i = list.Count - 2; i >= 0; i--)
        {
            if (list[i] == "-")
            {
                list[i] = (Convert.ToDouble(list[i - 1]) - Convert.ToDouble(list[i + 1])).ToString();
                list.RemoveAt(i + 1);
                list.RemoveAt(i - 1);
                i -= 2;
            }
        }
        stack.Clear();
        for (int i = 0; i < list.Count; i++)
        {
            stack.Push(list[i]);
        }
        while (stack.Count >= 3)
        {
            double right = Convert.ToDouble(stack.Pop());
            string op = stack.Pop();
            double left = Convert.ToDouble(stack.Pop());

            if (op == "<") result = (left < right) ? 1 : 0;
            else if (op == ">") result = (left > right) ? 1 : 0;
            else if (op == "<=") result = (left <= right) ? 1 : 0;
            else if (op == ">=") result = (left >= right) ? 1 : 0;
            else if (op == "==") result = (left == right) ? 1 : 0;

            stack.Push(result.ToString());
        }
        return Convert.ToDouble(stack.Pop());
    }

Я знаю, что, вероятно, будет более чистый способ сделать это, хотя id просто поделится первым взглядом, если кто-нибудь найдет его полезным.

ответил Fat-Wednesday 11 J0000006Europe/Moscow 2011, 15:34:16
0

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

x это число типа 1500 или 2100 или что-то в этом роде.

Функция

будет хранимой оценкой, такой как x> 1400 и x <1600

function = relation[0].Replace("and","&&").Replace("x",x);

DataTable f_dt = new DataTable();
var f_var = f_dt.Compute(function,"");

if (bool.Parse(f_var.ToString()) { do stuff  }
ответил Mr.Black 22 ndEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 22 Sep 2012 02:55:41 +0400 2012, 02:55:41
0

Нет. Вам нужно будет использовать какую-нибудь внешнюю библиотеку или написать свой собственный парсер. Если у вас есть время, я предлагаю написать свой собственный парсер, так как это довольно интересный проект. В противном случае вам нужно будет использовать что-то вроде bcParser .

ответил Tamas Czinege 2 TueEurope/Moscow2008-12-02T15:03:45+03:00Europe/Moscow12bEurope/MoscowTue, 02 Dec 2008 15:03:45 +0300 2008, 15:03:45
0

Краткий ответ: я так не думаю. Насколько мне известно, C # .Net компилируется (в байт-код) и не может оценивать строки во время выполнения. JScript .Net может, однако; но я бы все же посоветовал вам самостоятельно кодировать анализатор и оценщик на основе стека.

ответил 2 TueEurope/Moscow2008-12-02T15:02:03+03:00Europe/Moscow12bEurope/MoscowTue, 02 Dec 2008 15:02:03 +0300 2008, 15:02:03

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132