2012-02-17 15 views
37

Szukam prosty sposób ocenić proste wyrażenie matematyczne z łańcucha, tak:Ocenianie wyrażeń arytmetycznych z ciągiem w C++

3 * 2 + 4 * 1 + (4 + 9) * 6

chcę tylko + i * operacyjna powiększona ( i ) znaki. I * ma wyższy priorytet niż +.

+2

Czy to zadanie domowe? – 0605002

+1

... a jakie jest twoje pytanie? – 0605002

+0

Prawdopodobnie najlepiej jest go ocenić, analizując wyrażenie w jakiejś strukturze drzewa. –

Odpowiedz

25

myślę szukasz prostego recursive descent parser.

Oto bardzo prosty przykład:

const char * expressionToParse = "3*2+4*1+(4+9)*6"; 

char peek() 
{ 
    return *expressionToParse; 
} 

char get() 
{ 
    return *expressionToParse++; 
} 

int expression(); 

int number() 
{ 
    int result = get() - '0'; 
    while (peek() >= '0' && peek() <= '9') 
    { 
     result = 10*result + get() - '0'; 
    } 
    return result; 
} 

int factor() 
{ 
    if (peek() >= '0' && peek() <= '9') 
     return number(); 
    else if (peek() == '(') 
    { 
     get(); // '(' 
     int result = expression(); 
     get(); // ')' 
     return result; 
    } 
    else if (peek() == '-') 
    { 
     get(); 
     return -factor(); 
    } 
    return 0; // error 
} 

int term() 
{ 
    int result = factor(); 
    while (peek() == '*' || peek() == '/') 
     if (get() == '*') 
      result *= factor(); 
     else 
      result /= factor(); 
    return result; 
} 

int expression() 
{ 
    int result = term(); 
    while (peek() == '+' || peek() == '-') 
     if (get() == '+') 
      result += term(); 
     else 
      result -= term(); 
    return result; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 

    int result = expression(); 

    return 0; 
} 
+3

Nie sądzę, że rekursywna przyzwoitość jest dobra dla arytmetyki, ponieważ jest całkowicie rekurencyjna. – Pubby

+4

3 lata później - przepraszam za zombification! - w tym kodzie jest BŁĄD. Przekazanie temu wyrażeniu "-1 + 2" daje wynik -3. Aby to naprawić, w funkcji "factor()" obsługa bitów (peek() == '-') musi zwracać czynnik(), a nie wyrażenie(). –

+0

@JulianGold masz rację, dzięki. Dokona edycji. – Henrik

2

Napisałem bardzo proste narzędzie do sprawdzania wyrażeń w języku C# (minimalne zmiany są wymagane, aby było zgodne z C++). Opiera się na metodzie budowania drzewa ekspresji, tylko to drzewo nie jest faktycznie zbudowane, ale wszystkie węzły są oceniane na miejscu.

Można go znaleźć pod tym adresem: Simple Arithmetic Expression Evaluator

2

Podczas przeszukiwania biblioteki dla podobnego zadania znalazłem libmatheval. Wydaje się być właściwą rzeczą. Niestety, GPL, co jest dla mnie nie do przyjęcia.

2
import java.util.Deque; 
import java.util.LinkedList; 


public class EvaluateArithmeticExpression { 
    public static void main(String[] args) { 
     System.out.println(evaluate("-4*2/2^3+3")==-4*2/Math.pow(2, 3)+3); 
     System.out.println(evaluate("12*1314/(1*4)+300")==12*1314/(1*4)+300); 
     System.out.println(evaluate("123-(14*4)/4+300")==123-(14*4)/4+300); 
     System.out.println(evaluate("12*4+300")==12*4+300); 
    } 
    public static int evaluate(String s){ 
     Deque<Integer> vStack= new LinkedList<>(); 
     Deque<Character> opStack= new LinkedList<>(); 
     int i=0; 
     while(i<s.length()){ 
      if(isNum(s,i)) 
       i=getNum(s,vStack,i); 
      else if(isOp(s,i)) 
       i=doOp(s,opStack,vStack,i); 
     } 
     doOp(opStack,vStack); 
     return vStack.pop(); 
    } 
    private static int getNum(String s, Deque<Integer> vStack,int i){ 
     int sign=1; 
     if(s.charAt(i)=='-' || s.charAt(i)=='+') 
      sign=s.charAt(i++)=='-'?-1:1; 
     int val=0; 
     while(i<s.length() && isNum(s,i)) 
      val=val*10+s.charAt(i++)-'0'; 
     vStack.push(sign*val); 
     return i; 
    } 
    private static int doOp(String s, Deque<Character> opStack,Deque<Integer> vStack,int i){ 
     char op=s.charAt(i); 
     if(op=='(') 
      opStack.push(op); 
     else{ 
      if(op==')'){ 
       while(!opStack.isEmpty() && opStack.peekFirst()!='(') 
        doOp(opStack,vStack); 
       opStack.pop(); 
      } 
      else{ 
       while(!opStack.isEmpty() && prior(op)<=prior(opStack.peekFirst())) 
        doOp(opStack,vStack); 
       opStack.push(op); 
      } 
     } 
     return i+1; 
    } 
    private static int prior(char op){ 
     switch(op){ 
      case '+': 
      case '-': return 1; 
      case '*': 
      case '/': return 2; 
      case '^': return 4; 
     } 
     return 0; 
    } 
    private static void doOp(Deque<Character> opStack,Deque<Integer> vStack){ 
     int b=vStack.isEmpty()?0:vStack.pop(); 
     int a=vStack.isEmpty()?0:vStack.pop(); 
     char op=opStack.pop(); 
     int res=evaluate(a,b,op); 
     vStack.push(res); 
    } 
    private static int evaluate(int a, int b, char op){ 
     switch(op){ 
      case '+': return a+b; 
      case '-': return a-b; 
      case '/': return a/b; 
      case '*': return a*b; 
      case '^': return (int)Math.pow(a,b); 
     } 
     return 0; 
    } 
    private static boolean isNum(String s, int i){ 
     return '0'<=s.charAt(i) && s.charAt(i)<='9'; 
    } 
    private static boolean isOp(String s, int i){ 
     return "()+-*/^".contains(String.valueOf(s.charAt(i))); 
    } 
} 
+2

Kod powinien znajdować się w C++ ... – Eenoku

7

Wystarczy dodać inną alternatywę, za trudny TinyExpr tego problemu. Jest otwarty i samowystarczalny w jednym pliku kodu źródłowego. W rzeczywistości jest napisane w C, ale będzie kompilować czysto jak C++ w moim doświadczeniu.

rozwiązywania przykład wyraz z góry jest tak proste, jak:

#include "tinyexpr.h" 
#include <stdio.h> 

int main() 
{ 
    double answer = te_interp("3*2+4*1+(4+9)*6", 0); 
    printf("Answer is %f\n", answer); 
    return 0; 
} 
Powiązane problemy