2

重複の可能性:
高速ランタイム式パーサーが必要です

誰かが私のページのテキストボックスにx*y ^ zと入力して、背後のコードでその方程式を計算し、結果を取得するようにするにはどうすればよいですか?

4

6 に答える 6

5

組み込みの.NET機能を使用して、ユーザーhttps://stackoverflow.com/users/1670022/matt-crouchによる文字列としてのオペレーターからの回答:

「必要なのが単純な算術だけの場合は、これを実行してください。

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

編集:もう少し情報。System.Data.DataColumnクラスのExpressionプロパティについては、MSDNのドキュメントを確認してください。「式の構文」の内容は、算術演算子に加えて使用できるコマンドのリストの概要を示しています。(例:IIF、LENなど)。」

編集2:便宜上、これを次のような小さな関数に入れることができます。

public string Eval(string expr)
{
    var temp = new System.Data.DataTable();
    string result = null;
    try
    {           
        result = $"{temp.Compute(expr, string.Empty)}"; 
    }
    catch (System.Data.EvaluateException ex)
    {
      if (ex.Message.ToLower().Contains("cannot find column"))
            throw new System.Data.SyntaxErrorException($"Syntax error: Invalid expression: '{expr}'."
                                           + " Variables as operands are not supported.");
      else
            throw;
    }
    
    return result;
}

したがって、次のように使用できます。

Console.WriteLine(Eval("15 * (3 + 5) / (7 - 2)"));

期待される出力を与える:

24

エラーハンドラは、ここで許可されていない変数を使用することによって発生する例外を処理するのに役立つことに注意してください。例: -このコンテキストではあまり意味がない(データベースコンテキストでは使用していません)をEval("a")返す代わりに、"Cannot find column [a]""Syntax error: Invalid expression: 'a'. Variables as operands are not supported."

DotNetFiddleで実行します

于 2012-10-25T15:26:42.607 に答える
5

.NETには、任意の文字列を評価するための組み込み関数がありません。ただし、 NCalcという名前のオープンソースの.NETライブラリはそうです。

NCalcは、.NETの数式エバリュエーターです。NCalcは、静的または動的パラメーターやカスタム関数など、任意の式を解析して結果を評価できます。

于 2012-10-25T15:28:26.980 に答える
3

この問題には2つの主要なアプローチがあり、さまざまな回答に示されているように、それぞれにいくつかのバリエーションがあります。

  • オプションA:既存の数学的表現評価者を探す
  • オプションB:結果を計算するための独自のパーサーとロジックを作成します

これについて詳しく説明する前に、任意の数式の解釈は簡単な作業ではないことを強調するのが適切です。このような「おもちゃ」の文法以外の式の文法は、1つまたは2つの算術演算のみを受け入れ、括弧を使用できません。等

そのようなタスクは一見些細なことであると理解し、結局のところ、平均的な複雑さの算術式を解釈することは、さまざまなアプリケーション[したがって成熟したソリューションが利用可能である必要があるアプリケーション]の比較的頻繁な必要性であることを認め、おそらく実行しようとするのが賢明です「オプションA」を使用します。したがって、 NCalc
などの既製の式エバリュエーターに関するJedの2番目の推奨事項です。

ただし、時間をかけて、算術式の解析と解釈に関連するさまざまな概念と方法を、まるで自分の実装を作成するかのように理解しておくと便利な場合があります。

重要な概念は、形式文法の概念です。評価者が受け入れる算術式は、許可される算術演算のリストなどの一連の規則に従う必要があります。たとえば、評価者は、たとえば三角関数をサポートしますか、サポートする場合は、これにはたとえばatan2()も含まれますか。ルールは、オペランドを構成するものも示します。たとえば、45桁の数値を入力できるようになります。重要なのは、これらすべてのルールが文法で形式化されているということです。

通常、文法は、生の入力テキストから以前に抽出されたトークンで機能します。基本的に、プロセスのある時点で、一部のロジックは入力文字列を文字ごとに分析し、どの文字シーケンスが一緒になるかを決定する必要があります。たとえば、123 + 45 / 9.3式では、トークンは整数値123plus演算子、整数値45division演算子、そして最後に9.3実数値です。トークンを識別し、それらをトークンタイプに関連付けるタスクは、レクサーの仕事です。。レクサーは、文法に基づいて構築できます(トークンがレクサーによって生成される短い文字列である算術式パーサーの文法とは対照的に、「トークン」が単一の文字である文法)。

ところで、文法は算術式以外の多くのものを定義するために使用されます。コンピュータ言語は[かなり洗練された]文法に従いますが、コンピュータアプリケーションのさまざまな機能をサポートするためにドメイン固有言語(別名DSL)を導入することは比較的一般的です。

非常に単純な文法の場合、対応するレクサーとパーサーを最初から作成できる場合があります。しかし、遅かれ早かれ、文法が複雑になり、これらのモジュールを手書きすると、手間がかかり、バグが発生しやすくなり、さらに重要なことに読みにくくなる可能性があります。したがって、ルールのリスト(ジェネレーターに固有の構文で表現される)から(C、Java、C#などの特定のプログラミング言語で)レクサーとパーサーのコードを生成するスタンドアロンプ​​ログラムであるレクサージェネレーターとパーサージェネレーターの存在、多くのジェネレータは同様の構文を使用する傾向がありますが、大まかにBNFに基づいています)。

このようなレクサー/パーサジェネレーターを使用する場合は、複数のステップで作業を行います。-
最初に、文法の定義を(ジェネレーター固有の言語/構文で)書き込みます。-
この文法をジェネレーターで実行します。
-文法を書くことは厳密な演習であるため、上記の2つの手順を複数回繰り返すことがよくあります。ジェネレーターは、文法に書き込む可能性のある多くのあいまいさについて不平を言います。
-最終的にジェネレーターはソースファイルを生成します(C#などの目的のターゲット言語で)
-このソースはプロジェクト全体に含まれます
-プロジェクト内の他のソースファイルは、ジェネレーターによって生成されたソースファイルで公開されている関数を呼び出す場合があります。また、解析中に識別されたさまざまなパターンに対応するロジックを、ジェネレーターで生成されたコードに簡単に埋め込むことができます。
-プロジェクトは通常どおりにビルドできます。つまり、パーサーとレクサーが手書きで作成されたかのようになります。

これで、形式文法とコードジェネレーターを使用するプロセスの高さ20,000フィートのプレゼンテーションは終わりです。
パーサージェネレーター(別名コンパイラーコンパイラー)のリストは、このリンクにあります。C#での簡単な作業については、Ironyについても触れておきます。現時点で開業医になるつもりがなくても、これらのサイトを熟読して、これらの概念をよりよく理解することは非常に洞察に満ちているかもしれません。すでに述べたように、この特定のアプリケーションでは、既製の算術エバリュエーターがより良いアプローチである可能性が高い
ことを強調したいと思います。これらの主な欠点は

  • 許可される式の構文に関するいくつかの制限(許可される文法が制限的すぎる:stddev()と言う必要があるか、広すぎる:ユーザーに三角関数を使用させたくない。より成熟した評価者では、この問題に対処できる構成/拡張機能の形式になります。
  • そのようなサードパーティモジュールの学習曲線。うまくいけば、それらの多くは比較的「プラグアンドプレイ」である必要があります。
于 2012-10-25T17:21:00.213 に答える
1

このライブラリで解決http://www.codeproject.com/Articles/21137/Inside-the-Mathematical-Expressions-Evaluator

私の最終的なコード

Calculator Cal = new Calculator();
txt_LambdaNoot.Text = (Cal.Evaluate(txt_C.Text) / fo).ToString();

今、あるタイプが3 * 10 ^ 11のとき、彼は300000000000を取得します

于 2012-10-27T07:54:17.530 に答える
0

必要なのは、自分でやりたい場合は、式を解釈するコードの背後にあるスキャナー(レクサーとも呼ばれます) +パーサーです。または、JavaScript関数と同様に機能し、機能するサードパーティのライブラリを見つけることもできますeval(string)

こちらをご覧ください。再帰下降パーサーについて説明しています。この例はCで記述されていますが、記事で説明されているアイデアを理解すれば、 C#に簡単に適応できるはずです。

特にサポートする演算子の数が限られている場合は、思ったほど複雑ではありません。

利点は、実行される式を完全に制御できることです(Webサイトのエンドユーザーによる悪意のあるコードインジェクションを防ぐため)。

于 2012-10-25T15:25:18.783 に答える
0

式パーサーを実装する(またはサードパーティのソースを見つける)必要があります。これは簡単なことではありません

于 2012-10-25T15:25:54.947 に答える