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

时间:2009-08-25 05:41:52

标签: algorithm delphi math parsing

复制

  

Best algorithm for evaluating a mathematical expression?

是否有内置的Delphi函数可以将诸如'2 * x + power(x,2)'之类的字符串或任何等式转换为float?由于char X和power,StrToFloat引发了一个异常。

感谢。

6 个答案:

答案 0 :(得分:12)

免费JCL包括TEvaluator,一个由当前Delphi编译工程师编写的解析器。它可能比基于Windows脚本宿主的表达式评估程序更有效。

答案 1 :(得分:3)

您正在寻找可以评估表达式的内容。

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

但是,有一些外部工具可以帮助您。

例如:来自Pascal Scripting的免费RemObjects引擎可以执行您想要的操作。

- 的Jeroen

答案 2 :(得分:3)

很久以前(iirc 2005),一些SIG对各种表达式解析器进行了比较。结果如下:

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

包括Renate Schaaf的经典Turbo Pascal。

通常,速度较快的代码会生成本机代码,但是不可移植,可能需要修复DEP等。

自己写一个基本的并不是那么难,而且是许多编程课程中的标准任务。我在FPC / Delphi中编写了一个(现在是freepascal发行版的一部分,作为“符号”)并稍后将其转换为Java(作为Java字符串处理的练习。我有时会在晚上醒来时尖叫)。

其SVN位置

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

自我注意:我仍然有一些未完成的代码,用于添加用户可定义的函数和布尔算法。有一天必须完成它: - )

答案 3 :(得分:1)

不,除了解析字符串之外,它是不可能的。你如何将未知数x转换为浮动?

答案 4 :(得分:1)

在我们的SMImport套件中,我们编写了自己的表达式解析器/评估器,它基于Gasper Kozak的原始TFatExpression组件,gasper.kozak @ email.si

效果非常好。

答案 5 :(得分:1)

你可以使用我的单位,它仍然是基本但我仍然在写它,它现在做基本的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返回结果