Delphi中的数学表达式解析器?

6

重复

最佳算法用于求解数学表达式?

是否有内置的Delphi函数可以将诸如“2*x+power(x,2)”或任何方程转换为浮点数?StrToFloat会因字符X和power而引发异常。

谢谢。


请将标题改为更清晰易懂的名称。 - Pratik Deoghare
Parser10 是由 Renate Schaaf 开发的经典数学解析器,最后由 Hallvard Vassbotn 更新。请参见 Parsing a string formula to an integer result - LU RD
可能是评估数学表达式的最佳算法?的重复问题。 - tripleee
6个回答

12

免费的 JCL 包括 TEvaluator,它是由当前 Delphi 编译器工程师之一编写的解析器。它可能比基于 Windows 脚本主机的表达式求值器更加高效。


4

很久以前(如果我没记错的话是在2005年),有一个SIG对各种表达式解析器进行了比较。结果在以下链接中:

http://www.mindspring.com/~rbwinston/ParserTestFiles.zip

其中包括Renate Schaaf的经典Turbo Pascal。

一般来说,速度更快的生成本地代码,但是不可移植,并且可能需要修复DEP等问题。

自己编写基本的编译器并不难,在许多编程课程中是标准任务。我使用FPC / Delphi编写了一个(现在作为“Symbolic”包含在freepascal分发中),后来将其转换为Java(作为Java字符串处理练习。有时我仍然会在夜晚惊醒)。

它的SVN位置是

http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/symbolic/

自己留个记号:我还有一些未完成的代码需要添加用户定义函数和布尔运算。总有一天要完成它 :-)


3

您正在寻找一种可以评估表达式的工具。

由于Delphi是一种编译语言,它没有内置支持。

但是,有外部工具可以帮助您完成这项任务。

例如:来自RemObjects的免费Pascal脚本引擎可以满足您的需求。

--jeroen


1
如果只需要一个数学计算器,那么我认为脚本语言有些过度了。 - Marco van de Voort
2
因此,我对TEvaluator答案投了赞成票(: - Jeroen Wiert Pluimers
如果你认为Java字符串处理很糟糕,那就试试在Mac上使用Objective-C和Cocoa。<g> - Rudy Velthuis

1

不可能,除非解析字符串。你如何将未知数x转换为浮点数?


1
在我们的SMImport套件中,我们编写了自己的表达式解析器/求值器,它基于Gasper Kozak的原始TFatExpression组件,他的电子邮件是gasper.kozak@email.si。
非常好用。

0

你可以使用我的单元,它还很基础,但我还在编写中,目前它可以处理基本的BODMAS,但完成后我会发布整个单元。

Unit BODMAS;

Interface

  Uses
    System.SysUtils,
    Math;

  {
    !!!!!!!!!!!!!!!!!!!!!! GLOBAL DEFINITIONS !!!!!!!!!!!!!!!!!!!!
    EXPR = EXPRESSION
    CURRENTPOS = POSSITION OF THE CURRENT OPPERATOR OF WHICH MATH IS BEING PERFORMED

  }

  Function EvalFunction(Expr: String): String;

Implementation

  Function PrevOppPos(Expr: String; CurrentPos: Integer): Integer; // GETS THE PREVIOUS     OPPERATOR
    Var
      I: Integer;
      bSet: Boolean;
    Begin
      // THEORY
      // KEEP MOVING POSITIONS DOWN FROM I ... ( MEANING < WAY IN EXPR)
      // UNTIL AN OPPERATOR IS FOUND. IF NO OPPERATOR IS FOUND THE RESULT
      // WILL BE THE BEGINING OF THE EXPRESSION

      I := CurrentPos - 1;
      bSet := False;
      While ((I <= CurrentPos) AND (I >= 1)) OR (bSet = False) Do
        Begin
          // CHECK IF THE CHACHARACTER OF POSITION I IN EXPR IS AN OPPERATOR
          // "." AND "," IS NOT AN OPPERATOR!!
          If Expr[I] In ['(', ')', '+', '-', 'x', '/'] Then
            Begin
              Result := I;
              bSet := True;
              Dec(I); // Dec 1 more time to break loop
            End;
          Dec(I);
          If (I = 0) AND (NOT(bSet)) Then
            Begin
              Result := 1;
              bSet := True;
            End;
        End;
    End;

  Function NextOppPos(Expr: String; CurrentPos: Integer): Integer;
    Var
      I: Integer;
      bSet: Boolean;
    Begin
      // THEORY
      // KEEP MOVING POSITIONS UP FROM I ... ( MEANING > WAY IN EXPR)
  // UNTIL AN OPPERATOR IS FOUND. IF NO OPPERATOR IS FOUND THE RESULT
  // WILL BE THE LENGHT OF THE EXPRESSION

  I := CurrentPos + 1;
  bSet := False;

  While ((I <= Length(Expr)) AND (I >= CurrentPos)) OR (bSet = False) Do
    Begin
      // CHECK IF THE CHACHARACTER OF POSITION I IN EXPR IS AN OPPERATOR
      // "." AND "," IS NOT AN OPPERATOR!!
      If Expr[I] In ['(', ')', '+', '-', 'x', '/'] Then
        Begin
          Result := I;
          bSet := True;
          Inc(I); // Inc 1 more time to break loop
        End;
      Inc(I);
      If (I = Length(Expr) + 1) AND (NOT(bSet)) Then
        Begin
          Result := Length(Expr);
          bSet := True;
        End;
    End;

End;

  // EVALUATE BRACKET EXPRESSION
  Function EvalBracetExpr(Expr: String): String;
    Var
      OppCount, I: Integer;
      Ans: String;
      NewExpr: String;
      nOpp, pOpp, OppPos: Integer;
      nExpr, pExpr: String;
    Begin
      Ans := '';
      // EVALUATE EXPRESSION

      // ALL MULTIPLICATION IN BRACKETS
      While Pos('x', Expr) <> 0 Do
        Begin
          OppPos := Pos('x', Expr); // Opperator Position
          nOpp := NextOppPos(Expr, OppPos); // Next Opperator Position
          pOpp := PrevOppPos(Expr, OppPos); // Previous Opperator Position
          // COPY FROM THE OPPERATOR POS TO THE LENGTH OF THE EXPRESSION - THE POSITION     OF THE NEXT EXPRESSION
          // When Next opperator is the length of the expression
          If nOpp = Length(Expr) Then
            nExpr := Copy(Expr, OppPos + 1, Length(Expr) - (Length(Expr) - 1))
          Else
            nExpr := Copy(Expr, OppPos + 1, Length(Expr) - nOpp);
          // COPY FROM THE PREVIOUS OPPERATOR POS TO THE OPPERATOR POSITION -1
          pExpr := Copy(Expr, pOpp + 1, (OppPos - 1) - pOpp);
          Delete(Expr, pOpp, nOpp);
          Ans := Ans + FloatToStr(StrToFloat(pExpr) * StrToFloat(nExpr));
        End;

      // ALL ADDITION IN BRACKETS
      While Pos('+', Expr) <> 0 Do
        Begin
          OppPos := Pos('+', Expr); // Opperator Position
          nOpp := NextOppPos(Expr, OppPos); // Next Opperator Position
          pOpp := PrevOppPos(Expr, OppPos); // Previous Opperator Position
          // COPY FROM THE OPPERATOR POS TO THE LENGTH OF THE EXPRESSION - THE POSITION     OF THE NEXT EXPRESSION
          // When Next opperator is the length of the expression
          If nOpp = Length(Expr) Then
            nExpr := Copy(Expr, OppPos + 1, Length(Expr) - (Length(Expr) - 1))
          Else
            nExpr := Copy(Expr, OppPos + 1, Length(Expr) - nOpp - 1);
          // COPY FROM THE PREVIOUS OPPERATOR POS TO THE OPPERATOR POSITION -1
          pExpr := Copy(Expr, pOpp + 1, (OppPos - 1) - pOpp);
          Delete(Expr, pOpp, nOpp);
          Ans := Ans + FloatToStr(StrToFloat(pExpr) + StrToFloat(nExpr));
        End;

      Result := Ans;
    End;

  // EVALUTE ADDITION EXPRESSION
  Function EvalAddExpr(Expr: String): String;
    Var
      Expr1, Expr2: String;
    Begin
      Expr1 := Copy(Expr, 1, Pos('+', Expr) - 1);
      Expr2 := Copy(Expr, Pos('+', Expr) + 1, Length(Expr));
      Result := FloatToStr(StrToFloat(Expr1) + StrToFloat(Expr2));
    End;

  Function EvalFunction(Expr: String): String;
    Var
      bOPos, bCPos: Integer; // bracket Open/Closed Position
      sExpr: String;
      FinalExpr: String;
      OppPos: Integer;
      PrevOpp, NextOpp: Integer;
    Begin
      While Pos('(', Expr) <> 0 Do
        Begin
          // Find first open bracket
          bOPos := Pos('(', Expr);
          // Find first closed bracket
          bCPos := Pos(')', Expr);
          // Get the expression between the 2 brackets
          sExpr := Copy(Expr, bOPos, bCPos);
          // Remove sExpr from the Expression
          Delete(Expr, bOPos, bCPos + 1 - bOPos);
          // Concatenate the expression of what was before the bracket and that after     the bracket, as well as the result in the middle
          FinalExpr := Copy(Expr, 1, bOPos - 1) + EvalBracetExpr(sExpr) + Copy(Expr,     bOPos, Length(Expr));
          // Return the result
          Expr := FinalExpr;
        End;
      While Pos('+', Expr) <> 0 Do
        Begin
          // 1) Find the first + opperator in expression
          OppPos := Pos('+', Expr);
          // 2) find first part of expression
          PrevOpp := PrevOppPos(Expr, OppPos);
          // 3) find the next part of the expression
          NextOpp := NextOppPos(Expr, OppPos);
          // 4) get the full expression between the opperators
          //
          // if prev opp <> 1 then
          // move indicator 1 pos ahead
          If PrevOpp <> 1 Then
            Inc(PrevOpp);
          // if next opp <> len of expr then
          // move indicator 1 pos back
          If NextOpp <> Length(Expr) Then
            Dec(NextOpp);

          sExpr := Copy(Expr, PrevOpp, NextOpp);
          // 5) evaluating expression
          Delete(Expr, PrevOpp, NextOpp);
          FinalExpr := Copy(Expr, 1, PrevOpp-1) + EvalAddExpr(sExpr) + Copy(Expr,     PrevOpp, Length(Expr));
        End;
      Result := Expr;
    End;

End.

你将使用EvalFunction来返回结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接