Formel in zeichenkette einlesen und bearbeiten / auflösen



  • Hallo,

    habe folgendes prob:

    Ich will einen Taschenrechner basteln, der wie einer zu kaufen eine aufgabe entgegennimmt so z.B.:
    Bitte Aufgabe eingeben:

    1+(x-423)²-xv³=b+9x

    ok ich weis das ist ziemlich viel arbeit aber ich will auch nicht das mir jemand den code gibt um diese aufgabe zu lösen, nein ich brauche einen lösungsvorschlag um diese Eingegebene aufgabe( in einer zeile ) in einzelne variablen zu packen...

    wie etwa

    main(){

    char aufgabe[512];
    gets(aufgabe);

    was soll ich nun machen?

    getch();
    return 0
    }

    wie soll ich überhaut ermitteln was das erste zeichen ist? muss ich etwa jede stelle der zeichenkette mit if abfragen ob diese stelle ine 1 oder ein x oder ein wasauchimmer ist?

    gibt es eine andere methode ( ausser char aufgabe[512] ) eine aufgabe dieser art einzulesen und dann auszuwerten?

    bitte helft mir und danke schonmal im voraus



  • "parser"

    gut gemeinter rat: wenn du anfaenger bist, lass das lieber.



  • damit kann man doch nur "gramatiken" bearbeiten, ich meine eher aus einer zeichenkette z.b. 23,567 * x = 345,332 die einzelnen elemente auslesen:
    also einmal die

    23,567
    *
    x

    und die 345,332

    diese einzelnen elemente in variablen abspeichern( zumindestens die zahlenwerte ) und in einzelnen char variablen die operatoren und die variable 'x' speichern um dann die aufgabe nach z.B. x aufzulösen.

    wie kann ich das machen?



  • Und was ist bei "2+3*4" oder "2*(3+4)"?
    Sowas zu parsen is etwas komplizierter als nur den String in Token zu zerlegen und dann einfach auszuwerten.



  • währe schoneinmal ein ansatz, jedoch muss dabei zu beachten sein das evtl. 30 operationen auf der linen oder rechten seite des gleichheitszeichens stehen könnte und wie sollte ich da die zwischenräume untersuchen?
    ich dachte das ich ersteinmal jedes seichen von der ersten position im string an anylysiere ob es eine zahl oder eine varialble wie etwa 'x' oder 'y' ist, oder auch eine klammer bzw. operator. dann in eine char variable dann das selbe mit der 2. stelle, bis eine anderer typ von zeichen erscheint, dann speicher ich diesen typ in einen folgenden string wie etwa analys_2 und so weiter bis die kpl. zeichenkette "analysiert" wurde... doch das kann ja ziemlich lange dauern, ich wollte wissen wie dies schneller geht ( so etwas unter 100 zeilen... )



  • Googel mal nach "Postfix evaluation"



  • Tobias, STOP!

    du willst einen tokenizer, um die eingabe in tokens umzuwandeln (zahl, operator, variable, ...)
    dann willst du die tokens in relation stellen (einem operator die benachbarten zahlen oder variablen "ankleben"), damit du einen baum des ausdrucks hast.
    erst auf diesen baum kannst du ueberhaupt sinnvoll transformationen anwenden.



  • rhuig blut,

    ich weiss ja nichteinmal was tokenizer sind! Dann bin ich was programmieren angeht kein voll noob aber ich habe bisher nur ca 2 Monate erfahrungen mit dem direkten programmieren, indirekt also gelesen seit ca 2 Jahren oder mehr nur nie den nerv etwas umzusetzen, was nicht heißen soll das ich hinterm mond lebe aber evtl. einklein wenig mehr ins detail gehen. ( was die algorythmen angeht zum auflösen von ungleichungen und polynomen ist kein prob. die habe ich schon, ich kenne mich nur mit diesem c nicht wirklich aus und vor allem nicht mit den libs, bei pascal war das alles vieel einfacher... nur mal so kurz zu meiner erfahrung, also was sind nocheinmal tokenizer?



  • Ernst gemeinter Rat: Benutz google oder lass es ganz bleiben.





  • Hallo,

    ja dazu braucht es einen Parser bzw. Scanner, der deine Formelsprache analysiert und dann auswertet. Erstmal musst du die einzelnen Tokens deiner dort definierten Sprache erkennen und dann entsprechend Parsen. Wichtig dabei ist die Beachtung der Punkt-vor-Strich-Rechnung und Evaluierung von Sub-Ausdrücken.

    Als Beispiel hier mal der Sourcecode eines einfachen Infix-to-Postfix Compilers. Jedes Symbol dieser Sprache besteht aus einem Zeichen - damit entfällt das Scannen quasi gänzlich, und wird von der Funktion match() übernommen.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    /*
    	Sprachdefinition:
    
    	expr = expr + term		"+"
    	expr = expr - term		"-"
    	expr = term
    	term = 0			"0"
    	term = 1			"1"
    	term = 2			"2"
    	term = 3			"3"
    	term = 4			"4"
    	term = 5			"5"
    	term = 6			"6"
    	term = 7			"7"
    	term = 8			"8"
    	term = 9			"9"
    */
    
    char	lookahead;
    int		pos = 0;
    char	expression[20+1];
    
    void error()
    {
    	printf("Error!\n");
    }
    
    void match( char t )
    {
    	if( lookahead == t )
    	{
    		pos++;
    		lookahead = expression[pos];		
    	}
    	else
    		error();
    }
    
    void term()
    {
    	switch( lookahead )
    	{
    		case '0':
    		case '1':
    		case '2':
    		case '3':
    		case '4':
    		case '5':
    		case '6':
    		case '7':
    		case '8':
    		case '9':
    			printf("%c", lookahead);
    			match( lookahead );
    			break;
    		default:
    			error();
    			break;
    	}
    }
    
    void expr()
    {
    	term();
    	while(true)
    	{
    		switch( lookahead )
    		{
    			case '+':
    				match('+');
    				term();
    
    				printf("+");
    				break;
    			case '-':
    				match('-');
    				term();
    
    				printf("-");
    				break;
    			default:
    				return;
    
    		}
    	}
    }
    
    int main ( int argc, char** argv )
    {
    	strcpy( expression, "9-5+2");
    	lookahead = *expression;
    
    	expr();
    	printf("\n");
    	getchar();
    
    	return 0;
    }
    

    ~code_pilot



  • danke,
    wenn ich das richtig verstanden habe muss ich mir einen eigenen compiler bauen der dann das macht was ein wissenschaftlicher tschenrechner macht und solche formeln wie angegeben ausrechnet bzw. umstellt oder ungleichungen auflöst.

    gibt es denn überhauptkeine möglichkeit einzelne zeichen aus char quest[1025]
    vorher eingegeben mit gets(quest) auszulesen?

    ich kann doch mit strlen die länge des eingegebenen strings bestimmen, dann könnte ich doch mit scanf(quest[2]); so das dritte zeichen der kette auslesen und dann in eine char variable an ps 3 schieben wenn die ersten 3 ziffern dieser kette dann z.B. 835 ist könnte ich dann diesen string mit atoi in einen int verwandeln und dann damit rechnen.

    oder ist diese möglichkeit absolut unmöglich? wenn ja gibt es nicht doch irgendeine andere möglichkeit dieses prob zu lösen ohne gleich informatik zu studieren.



  • Tobias_N schrieb:

    damit kann man doch nur "gramatiken" bearbeiten [...]

    Ein mathematischer Term wird auch nach ganz bestimmten Regeln aufgebaut. Diese kann man durch eine Grammatik beschreiben. Ist also genau das was Du brauchst.

    Schau hier: http://epaperpress.com/lexandyacc/. Das sind Tools die dir helfen werden.



  • @Tobias:

    Ein einfacher Scanner, der Zahlen und Operatoren unterscheiden kann ist folgender (ist jetzt nur nicht mit dynamischer Speicherverwaltung!):

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define NUMBER 0
    #define OPERATOR 1
    
    typedef struct
    {
    	int type;
    	char tok[255];
    	int len;
    } token;
    
    int scan( token* t, char* expression )
    {
    	int i;
    	int tp = 0;
    
    	for( i = 0; i < strlen( expression ); i++ )
    	{
    		switch( expression[i] )
    		{
    			case '0':
    			case '1':
    			case '2':
    			case '3':
    			case '4':
    			case '5':
    			case '6':
    			case '7':
    			case '8':
    			case '9':
    				if( tp > 0 && t[tp-1].type == NUMBER )
    				{
    					t[tp-1].tok[t[tp-1].len] = expression[i];
    					t[tp-1].tok[t[tp-1].len+1] = '\0';
    
    					t[tp-1].len++;
    				}
    				else
    				{
    					t[tp].type = NUMBER;
    
    					t[tp].tok[0] = expression[i];
    					t[tp].tok[1] = '\0';
    
    					t[tp].len = 1;
    
    					tp++;
    				}
    				break;
    			case '+':
    			case '-':
    			case '*':
    			case '/':
    				if( tp > 0 && t[tp-1].type == OPERATOR )
    				{
    					//Weiterer Operator ist nicht erlaubt!
    					printf("Syntaxfehler!\n");
    				}
    				else
    				{
    					t[tp].type = OPERATOR;
    
    					t[tp].tok[0] = expression[i];
    					t[tp].tok[1] = '\0';
    
    					t[tp].len = 1;
    
    					tp++;
    				}
    				break;
    		}
    	}
    
    	return tp;
    } 
    
    int main( int argc, char** argv )
    {
    	char exp[255+1];
    	token tokens[100];
    	int cnt, i;
    
    	printf("Expression: ");
    	gets( exp );
    
    	cnt = scan( tokens, exp );
    
    	printf("\n");
    
    	for( i = 0; i < cnt; i++ )
    	{
    		printf("%s ist vom Typ %d\n", tokens[i].tok, tokens[i].type );
    	}
    
    	//Aber hier wird dann später geparst...
    
    	getchar();
    	return 0;
    }
    

    Anhand der Ausgabe kann man deutlich erkennen, das der Scanner die Tokens korrekt erkannt hat. Nach dem Scan folgt dann das Parsen, wobei der Parser selber seine Tokens immer bei Bedarf durch den Scanner ermitteln kann, d.h. der Parser ermittelt ein Token, entscheidet, was er damit tun soll, und ermittelt dann bei bedarf das nächste Token. Das kann man aber machen wie man lustig ist.

    Testlauf:

    Expression: 123*6+55-3

    123 ist vom Typ 0
    * ist vom Typ 1
    6 ist vom Typ 0
    + ist vom Typ 1
    55 ist vom Typ 0
    - ist vom Typ 1
    3 ist vom Typ 0

    ~cp



  • danke,

    ich kann nur keine gleichungen eingeben à la 3x*2y=7(2+y)²

    mir werden dann die werte zugewiesen, jedoch wird u.a. das gleichheitszeichen einfach missachtet, ich spiele mal ein wenig mit dem code herrum und halte dich auf dem laufenden.

    p.S. hast du eine ahnung wie ich mit pointern einzelne elemente eines char strings auslesen und in variablen speichern kann? ich habe mir gerade eine datei im netz angeschaut und dort wurde mir etwas in dieser richtung erklärt
    (http://www.guardian-online.de/c-kurs/) dann pointer(i)



  • Hallo Tobias,

    ich denke du solltest dafür eher richtig C programmieren lernen bevor du dich solch einer Aufgabe zuwendest.

    Pointer sind eine tolle Sache - wenn man weiss, wie man damit umgeht.

    Du kannst z.B. einen String Zeichenweise so ausgeben:

    char bla[255];
    char* x;
    
    strcpy( bla, "Hello World and everything is fine!");
    for( x = bla; *x != '\0'; x++ )
    {
          printf("Pointer is %c\n", *x);
    }
    

    Das Gleichheitszeichen erkennt der o.g. Scanner auch (noch) nicht. Das muss man erst alles einbauen.

    Gruß
    ~code_pilot



  • ja das habe ich schon einige male gehört, doch wann kann ich sagen das ich c programmieren kann ( deiner definition nach ), ich lese zwar seit einiger zeit haufenweise bücher über diese und andere sprachen, jedoch habe ich (peinlicher-)weise bis dato noch nie den übergang zuum schreiben von programmen gemacht; wusste auch um ehrlich zu sein nicht was ich maches sollte bis wir die lineare algebra und analysis durchnahmen.



  • Tobias_N schrieb:

    ja das habe ich schon einige male gehört, doch wann kann ich sagen das ich c programmieren kann ( deiner definition nach )

    Dann, wenn du dir bei der Umsetzung von Programmen nur noch Gedanken über das Problem selbst machst und NICHT über Details der Sprache (so wie du z.B. bei den Zeigern).
    Du solltest wirklich erst die Sprache verstanden haben, bevor du sowas wie einen Scanner schreibst.



  • Man lernt eine Programmiersprache nicht durch Bücher, sondern durch Praxis. Oder wie sagt man doch gleich: Übung macht den Meister! Und Bücher schmökern ist kein üben, sondern Grundlagen und Theorie. Praxis braucht's!

    Fang vielleicht erstmal mit kleinen Dingen an. Probiere aus, was für tolle Dinge man mit Pointer machen kann. Lerne, Speicher dynamisch zu verwalten. Lerne professionelle Lösungen, Kniffe und Techniken anhand der Sourcecodes anderer oder durch Übung.

    Ich programmiere jetzt seid 4 Jahren in C, insgesamt programmiere ich seit 7 Jahren. Und ich lerne heute noch nicht aus. Und das ist auch der reiz dabei: Neue Dinge erschaffen, neue Dinge enddecken!

    Das macht Spaß! 😃 😃 😃

    ~cp



  • Du kannst C programmieren wenn du keine Fragen mehr dazu hast 😉


Anmelden zum Antworten