VB.Net Klammern auflösen

schmidmi

Lt. Commander
Registriert
Feb. 2007
Beiträge
1.823
Wie kann ich möglichst effektiv Klammern aus einer Rechnung auflösen?
Wenn die Rechnung z.B. so aussieht (3+2)*(5*(6-4)) dann sollten ja zuerst die inneren Klammern ausgerechnet werden um auf das richtige Ergebnis zu kommen.

Mein Ansatz bisher:
Zuerst gehe ich die Zeile durch bis ich die erste öffnende Klammer finde. Deren Position merke ich mir und suche dann nach der nächsten Klammer. Wenn es eine schließende Klammer ist speichere ich alles was dazwischen steht in einer anderen Variable, lösche die beiden Klammern und gehe weiter die Zeile durch. Wenn ich auf eine zweite öffnende Klammer stoße wird die Variable für die öffnende Klammer überschrieben und weiter gesucht.

Nach dem ersten Durchlauf sieht die Zeile dann wie folgt aus:

Zwischenwert_1 * (5 * Zwischenwert2)

Jetzt werden die Zwischenwerte errechnet
Ergebnis:

5 * (5 * 2)

Dann rufe ich die Funktion wieder auf um erneut nach Klammern zu suchen.

5 * Zwischenwert_1

5 * 10

Wenn keine Klammern mehr gefunden werden, berechne ich das Ergebnis.


Gibt es dafür bessere Lösungsansätze? :confused_alt:
 
Es gibt eben die Möglichkeit einen vollwertigen Parser zu schreiben... ob das für einen Anfänger einfacher ist wage ich allerdings zu bezweifeln :-)
 
das verfahren wie du es hier vorstellst kann ich nicht empfehlen.
du solltest dir mal ansehen wie ein lexer und ein parser funktionieren. dann kannst du aus dem ausdruck einen parser-baum generieren, mit dem du ganz einfach das ergebnis ausrechnen kannst. das hat zudem den vorteil, dass du bestimmte operatoren wie z.b. * oder + unterschiedliche präzedenzen geben kannst, dass regeln wie punkt vor strich beachtet werden etc.
kugg dich mal im netz um.
 
schau dir mal Lua an...

EDIT: bietet alles was du brauchst
 
Zuletzt bearbeitet:
das Auflösen solcher gleichungen ist prinzipiell gar nicht so kompliziert. Ich empfehle folgendes Vorgehen:

1. Separieren von Operatoren und Operanden - man legt also einen char-Array an, in dem alle Operanden hintereinander stehen und einen double-Array in dem alle Zahlenwerte liegen.

2. Suche im Operatoren-Array die tiefste Klammer-Ebene

3. Rechne die Operation in dieser ebene aus (hierbei punkt- vor Strichrechnung!). Wenn hier Operationen aufgelöst wird, können die Operatoren aus dem CharArray entfernt werden, und aus jeweils 2 Operanden wird einer. Dies machst du solange, bis in der Klammerebene nur noch ein Wert steht. Dann kansnt du diese Klammerebene auch entfernen, dann von vorn

edit: ich habe sowas mal in C gemacht, vielleicht hilft dir das. In der Version werden Klammern, +,-,*,/ und die logischen Operanden &, |, !,>=,<=,!=,> und < unterstützt (jeweils Berechnung mit 1 oder 0 für true und false)
Code:
#include <string.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>

#define EVAL_MAX 255

double calc(double o1, double o2, char op)
{
       if(op=='*')
       {
                  return o1*o2;
       }
       else if(op=='/')
       {
                  return o1/o2;
       }
       else if(op=='+')
       {
                  return o1+o2;
       }
       else if(op=='-')
       {
                  return o1-o2;
       }
       //and
       else if(op=='&')
       {
            if(o1 && o2)return 1.0;
            else return 0.0;
       }
       //or
       else if(op=='|')
       {
            if(o1 || o2)return 1.0;
            else return 0.0;
       }
       //nicht
       else if(op=='!')
       {
            if(!o1)return 1.0;
            else return 0.0;
       }
       //größer-gleich
       else if(op=='g')
       {
            if(o1 >= o2) return 1.0;
            else return 0.0;
       }
       //kleiner-gleich
       else if(op=='k')
       {
            if(o1 <= o2) return 1.0;
            else return 0.0;
       }
       //ungleich
       else if(op=='u')
       {
            if(o1 != o2)return 1.0;
            else return 0.0;
       }
       //größer
       else if(op=='>')
       {
            if(o1 > o2)return 1.0;
            else return 0.0;
       }
       //kleiner
       else if(op=='<')
       {
            if(o1 < o2)return 1.0;
            else return 0.0;
       }      
       
       return -1;

}

int execute_symbol(double *vals, char *ops, int *vals_am, int *ops_am, int symbol)
{
    // suchen der zugeörigen Werte
     int first_value=0;
     int k;
     for(k=0;k<*ops_am;k++)
     {
             if(k>=symbol)break;
             if(ops[k]!='(' && ops[k]!=')')first_value++;
     }
     
     //Berechnung der Operation
     double e = calc(vals[first_value],vals[first_value+1],ops[symbol]);
     
     //Einträge ersetzen
     //Werte
     vals[first_value]=e;
     //NOT hat nur einen zugehörigen Zahlenwert
     //Ist der Operator '!' darf der 2. Wert nicht entfernt werden
     if(ops[symbol]!='!')
     {
         for(k=first_value+1;k<*vals_am;k++)
         {
              vals[k]=vals[k+1];
         }
         *vals_am = *vals_am-1;
     
     }
     //Operationen
     for(k=symbol;k<*ops_am;k++)
     {
          //dfhgb
          ops[k]=ops[k+1];
     }
     *ops_am = *ops_am-1;
     
     return 1;
}

int simplify(double *vals, char *ops, int *vals_am, int *ops_am)
{
    //nicht mehr zu vereinfachen: nur noch ein wert vorhanden
    if(*vals_am==1) return 0;
    
    //operatoren nach überflüssigen Klammern durchsuchen:
    int i;
    for(i=0;i<*ops_am;i++)
    {
         //suche nach: "()"
         if(ops[i]=='(' && ops[i+1]==')')
         {
              for(int j=i;j<*ops_am;j++)
              {
                      ops[j]=ops[j+2];        
              }
              *ops_am = *ops_am-2;
         }
    }
    
    int max_klammer=0,curr_klammer=0;
    int max_klammer_p=0;
    
    for(i=0;i<*ops_am;i++)
    {
         if(ops[i]=='(')curr_klammer++;
         else if(ops[i]==')')curr_klammer--;
         if(curr_klammer>max_klammer)
         {
              max_klammer=curr_klammer;
              max_klammer_p=i;
         }
    }
    
    //nicht aller klammern vom Benutzer geschlossen
    if(curr_klammer>0)
    {
          int a;
          for(a=0;a<curr_klammer;a++)
          {
                  ops[*ops_am+a]=')';
          }
          ops_am+=a;
          
    }
    //zuviele Klammern geschlossen
    else if(curr_klammer<0) return -2;
    
    //tiefste Klammerebenen Bearbeiten
    if(max_klammer>0)
    {
        //NOT vorhanden? -> einen Auflösen
        for(i=0;1;i++)
        {
             if(ops[max_klammer_p+i]==')')break;
             else if(ops[max_klammer_p+i]=='!')
             {
                 execute_symbol(vals, ops, vals_am, ops_am, max_klammer_p+i);
                 return 1;
             }
        }
        
        //Punktrechnung vorhanden? -> einen Auflösen
        for(i=0;1;i++)
        {
             if(ops[max_klammer_p+i]==')')break;
             else if(ops[max_klammer_p+i]=='*' || 
                ops[max_klammer_p+i]=='/')
             {
                  execute_symbol(vals, ops, vals_am, ops_am, max_klammer_p+i);
                  return 1;
             }
        }
        
        //Strichrechnung vorhanden? -> einen Auflösen
        for(i=0;1;i++)
        {
             if(ops[max_klammer_p+i]==')')break;
             if(ops[max_klammer_p+i]=='+' || 
                ops[max_klammer_p+i]=='-')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, max_klammer_p+i);
                     return 1;
                }
        }
        
        //[Größer/kleiner]-[un/gleich] vorhanden? -> einen Auflösen
        for(i=0;1;i++)
        {
             if(ops[max_klammer_p+i]==')')break;
             else if(ops[max_klammer_p+i]=='g' || 
                ops[max_klammer_p+i]=='k' ||
                ops[max_klammer_p+i]=='>' ||
                ops[max_klammer_p+i]=='<' ||
                ops[max_klammer_p+i]=='u' ||
                ops[max_klammer_p+i]=='=')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, max_klammer_p+i);
                     return 1;
                }
        }
        
        //AND vorhanden? -> einen Auflösen
        for(i=0;1;i++)
        {
             if(ops[max_klammer_p+i]==')')break;
             else if(ops[max_klammer_p+i]=='&')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, max_klammer_p+i);
                     return 1;
                }
        }
        
        //OR vorhanden? -> einen Auflösen
        for(i=0;1;i++)
        {
             if(ops[max_klammer_p+i]==')')break;
             else if(ops[max_klammer_p+i]=='|')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, max_klammer_p+i);
                     return 1;
                }
        }
        
    }
    //keine Klammern gefunden
    else
    {
        //NICHT (NOT) vorhanden?
        for(i=0;1;i++)
        {
             if(i==*ops_am)break;
             if(ops[i]=='!')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, i);
                     return 1;
                }
        }
        //Punktrechnung vorhanden?
        for(i=0;1;i++)
        {
             if(i==*ops_am)break;
             if(ops[i]=='*' || 
                ops[i]=='/')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, i);
                     return 1;
                }
        }
        
        //strichrechnung vorhanden?
        for(i=0;1;i++)
        {
             if(i>=*ops_am)break;
             if(ops[i]=='+' || 
                ops[i]=='-')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, i);
                     return 1;
                }
        }
        
        //[Größer/kleiner]-[un/gleich] vorhanden?
        for(i=0;1;i++)
        {
             if(i>=*ops_am)break;
             if(ops[i]=='g' || 
                ops[i]=='k' ||
                ops[i]=='>' ||
                ops[i]=='<' ||
                ops[i]=='u' ||
                ops[i]=='=')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, i);
                     return 1;
                }
        }
        
        //UND vorhanden?
        for(i=0;1;i++)
        {
             if(i>=*ops_am)break;
             if(ops[i]=='&')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, i);
                     return 1;
                }
        }
        
        //ODER vorhanden?
        for(i=0;1;i++)
        {
             if(i>=*ops_am)break;
             if(ops[i]=='|')
                {
                     execute_symbol(vals, ops, vals_am, ops_am, i);
                     return 1;
                }
        }
    }
    
    return -1;
}

double eval(char *exp)
{
    //alle Leerzeichen entfernen
    unsigned int laenge = strlen(exp);
	char *temp = (char*) malloc(sizeof(char)*laenge);
    int a=0;
	for(int i=0;1;i++)
	{
		if(exp[i]!=' ')
		{
			temp[a]=exp[i];
			a++;
		}
		if(temp[a]=='\0' || temp[a]=='\n')
		{
			temp[a]='\0';
			break;
		}
	}
	
	strcpy(exp,temp);
	//printf("|exp:'%s'\n",exp);
	//getch();
	
	double vals[EVAL_MAX];
	char ops[EVAL_MAX];
	int vals_am=0,ops_am=0;
	
	//alle zahlenwerte einlesen
	char *p;
	for(int k=0;1;k++)
    {
            if(exp[k]>=48 && exp[k]<=57)
            {
                          vals[0] = strtod(&exp[k],&p);
                          break;
            }
            else if(k>=laenge)
            {
                 printf("kein gueltiger mathematischer Ausdruck!");
                 return 0.0;
            }
    }
	for(vals_am=1;vals_am<EVAL_MAX;vals_am++)
	{
         if(*p=='\0')break; //ende des Ausdrucks
         //Überspringe Klammern und Rechenzeichen
         while(1)
         {
              //drei Zeichen: AND
              if(*p=='A'&& *(p+sizeof(char))=='N'&& *(p+2*sizeof(char))=='D')
                 {p += 3*sizeof(char); break;}
                 
              //zwei Zeichen: <= >= OR == <>
              else if(
                    *p=='<' && *(p+sizeof(char))=='='
                 || *p=='>' && *(p+sizeof(char))=='='
                 || *p=='=' && *(p+sizeof(char))=='='
                 || *p=='<' && *(p+sizeof(char))=='>'
                 || *p=='O' && *(p+sizeof(char))=='R')
                 {p += 2*sizeof(char); break;}
                 
             //Ein Zeichen: ( ) + - * / ! < >
             if(*p=='(' || *p==')' ||*p=='+' || *p=='-' ||*p=='*' || *p=='/' ||*p=='!' ||*p=='<' || *p=='>')
                  {p += sizeof(char); break;}
                  
            //printf("Vergleiche: %c,%c,%c\n",*p,*(p+sizeof(char)),*(p+2*sizeof(char)));
                 
         }
         char *d;
         vals[vals_am] = strtod(p, &d);
         p=d;
         
    }
    
    int n;
    
    //alle Operationen einlesen:
    ops_am=0;
    for(n=0;ops_am<EVAL_MAX;n++)
    {
         if(exp[n]=='\0')break;
         else if(exp[n]=='(' ||
                 exp[n]==')' ||
                 exp[n]=='+' ||
                 exp[n]=='-' ||
                 exp[n]=='*' ||
                 exp[n]=='/')
                 {
                      //printf("exp[%i]=%c\n",n,exp[n]);
                      ops[ops_am]=exp[n];
                      ops_am++;
                 }
         else if(exp[n]=='A' && exp[n+1]=='N' && exp[n+2]=='D')
         {
              ops[ops_am]='&';
              n+=2;
              ops_am++;
         }
         else if(exp[n]=='O' && exp[n+1]=='R')
         {
              ops[ops_am]='|';
              n++;
              ops_am++;
         }
         else if(exp[n]=='N' && exp[n+1]=='O' && exp[n+2]=='T')
         {
              ops[ops_am]='!';
              n+=2;
              ops_am++;
         }
         else if(exp[n]=='>' && exp[n+1]=='=')
         {
              ops[ops_am]='g';
              n++;
              ops_am++;
         }
         else if(exp[n]=='<' && exp[n+1]=='=')
         {
              ops[ops_am]='k';
              n++;
              ops_am++;
         }
         else if(exp[n]=='<' && exp[n+1]=='>')
         {
              ops[ops_am]='u';
              n++;
              ops_am++;
         }
         else if(exp[n]=='=' && exp[n+1]=='=')
         {
              ops[ops_am]='=';
              n++;
              ops_am++;
         }
         else if(exp[n]=='>')
         {
              ops[ops_am]='>';
              n++;
              ops_am++;
         }
         else if(exp[n]=='<')
         {
              ops[ops_am]='<';
              n++;
              ops_am++;
         }
         

    }
    /*
    gotoxy(1,11);
    printf("Berechnung:%s       \n",exp);
    printf("%i Werte:",vals_am);
    for(i=0;i<vals_am;i++)
    {
            printf("%lf,",vals[i]);
    }
    printf("                \n%i Ops:",ops_am);
    for(i=0;i<ops_am;i++)
    {
            printf("%c,",ops[i]);
    }
    
    //*/
    
    //den Ausdruck sooft vereinfachen, bis nur noch eine Zahl überig ist
    while(1)
    {
         //den Ausdruck 1x vereinfachen
         int c=simplify(vals, ops, &vals_am, &ops_am);
         //Ausdruck besteht nur noch aus einem Wert -> ende
         //ODER: Fehler bei a<0
         if(c<=0) break;
         //printf("values:%i",vals_am);
    }
    
    
    if(a<0)
    {
           if(a==-2)printf("Ungueltige Klammerbilanz");
           return 0.0;
    }
    
    
    //printf("              \nErgebnis: %lf      ",vals[0]);

    return vals[0];
}
 
Zuletzt bearbeitet:
Danke für die Tipps.
Werde mich nächste Woche mal daran versuchen.
 
Zurück
Oben