Einen string in Token zerlegen



  • Hallo Leute,

    ich möchte einen string, wie z.b."22+1*2" so zerlegen lassen, dass 22 ein integer ist,+ ein char,1 ein integer,*ein char und 2 wieder ein integer.

    Gibt es da eine Funktion,die mir dabei helfen kann?



  • evtl. std::istream::get()

    Oder du bedienst dich eines fertigen Lexer/Parser Generators oder einer entsprechenden Bibliothek...



  • Ich habe es mit der Funktion strtok() ausprobiert. Aber diese scheint nur an den white_space zeichen zu splitten. Wenn ich "2+2*2" splitten lasse, gibt er den kompletten string "2+2*2" einfach wieder aus.

    Wenn ich es stattdessen mit dem string "Hello World 123" mache trennt er korekt und gibt:
    "Hello
    World
    123"

    aus.

    Wie muss ich den Code:

    #include "../../../std_lib_facilities.h"
    #include "conio.h"
    
    #include <stdio.h>
    #include <string.h>
    
    int main ()
    {
      char str[] ="2+2*2";
      char * pch;
      printf ("Splitting string \"%s\" into tokens:\n",str);
      pch = strtok (str," ,.-");
      while (pch != NULL)
      {
        printf ("%s\n",pch);
        pch = strtok (NULL, " ,.-");
      }
      getch();
      return 0;
    }
    

    modifizieren,dass er auch "2+2*2" in 2,+,2,*,2 splittet?

    Ich hatte an folgendes gedacht: Eine Funktion, die nachträglich in den string whitespacezeichen einfügt. Gibt es so etwas?

    Bsp: string = "2+2*2" , die Funktion würde dann nachträglich folgendes machen:
    string = "2 + 2 * 2". Dann würde nämlich auch die strtok() Funktion funzen.

    Gibt es solch eine "white-space-maker" Funktion?



  • Na überleg dir doch mal was du genau machen willst. Du musst deinem Code eben beibringen, welche Zeichen zu welcher Art von Token gehören können, damit er dann entscheiden kann, wo ein Token aufhört und ein neues beginnt...



  • Im Grunde möchte ich mit dieser white-space sache erreichen,dass zahlen mit mehr als einer Ziffe z.b. 125 auch direkt als 125 dann weiterverwendet werden können und nicht die ziffern einzeln als token dort liegen und sie erst "aufwendig" zusammengesetzt werden müssen. Das könnte man so lösen,dass die "white-space-maker" Funktion nur die whitespaces vor und nach den Operatoren setzt, dann wäre es egal wie groß die zahl ist, sie wäre komplett.
    Danach würde dann die strtok drüber gehen und alles korekt aufspalten.

    Wichtig wäre mir zu wissen, ob es so eine white-space-maker Funktion (oder wie auch immer) gibt und wie ich an sie rankomme. 🙂



  • Was genau sollte diese white-space-maker Funktion tun!? Du hast doch dein Problem eh schon erkannt, wo genau liegt jetzt das Problem eine Lösung dafür zu implementieren. Du willst also dass die ganze Zahl als ein Token genommen wird und nicht nur einzelne Ziffern? Na dann machs doch genau so!? Du musst dir eben merken ob du gerade eine Ziffer gelesen hast und wenn ja, fügst du jede weitere Ziffer an die vorhergehenden Ziffern an, um deine Zahl zu erhalten!?



  • Golfi1812 schrieb:

    ich möchte einen string, wie z.b."22+1*2" so zerlegen lassen, dass 22 ein integer ist,+ ein char,1 ein integer,*ein char und 2 wieder ein integer.

    Gibt es da eine Funktion,die mir dabei helfen kann?

    Dieser Expression-Parser ist (wahrscheinlich) genau das was Du brauchst.

    Gruß
    Werner



  • Danke Werner, das habe ich gesucht,doch bei einer Sache brauche ich noch Hilfe:

    Kann man deinen Parser so umschreiben, dass man ihn einfach in ein Programm einbinden kann?

    Bsp: Ich habe ein Programm, es liest Variablen ein ,gibt sie aus und so weiter.
    doch dann muss die Eingabe des Benutzers z.b.2+22 ausgrechnet werden.
    Dann baut man an dieser Stelle im Programm sozusagen eine Brücke ein, die die Einagbe (2+2
    2) an deinen Parser sendet und der Parser dann das Endergebniss in eine Variable zurückliefert.

    Wie müsste ich deinen Parser dann umschreiben, dass er wie eine Funktion mit einem Argument "gefüttert" werdden kann und dann das Endergebniss zurückliefert?



  • Den Parser kannst Du so wie er ist nutzen. Der Königsweg sähe so aus, dass an der Stelle, wo Du die Benutzer-Eingabe liest, ein std::istream zur Verfügung steht. Also:

    std::istream input( /*der User*/ );
        double val;
        if( input >> expression( val ) )
            // der Inhalt von 'val' enthält das Ergebnis
    

    das ist alles.

    Falls Du keinen std::istream hast, so schreibe den Text einfach in einen istringstream.

    std::string userEingabe = /* Dein Ding */;
        std::istringstream input( userEingabe );
        double val;
        if( input >> expression( val ) )
            // der Inhalt von 'val' enthält das Ergebnis
    

    siehe dazu auch das main() am Ende meines Listing, hinter dem Link oben.

    Gruß
    Werner



  • Golfi1812, "Dein" Code ist doch nur der hier, den Du mit

    #include "../../../std_lib_facilities.h"
    #include "conio.h"
    ::
    char str[] ="2+2*2";
    ::
    getch();
    

    angereichert hast. Wie auch in Deinem vorherigen Thread kann man hier sehen, dass Du Dir der Bedeutung des Wortes "Token" nicht wirklich bewusst bist. Was ein Token im konkreten Fall ist und was nicht, ist Definitionssache. Es gibt keine universelle Token-Parsing-Routine, die eine Zeichenkette in mehrere aufteilt. Das liegt daran, dass, je nachdem, was Du machen willst, diese Zerlegung anders aussehen wird. strtok orientiert sich da an "Begrenzungszeichen" (Delimiter), die Du selbst festlegen kannst und es ja auch tust (mit " ,.-" bei strtok).

    Was ich sehr schade finde, ist, dass Du ein tolles, modernes C++ Buch vor Deiner Nase liegen hast (Stroustrups "Einführung in die Programmierung mit C++") und trotzdem per Copy&Paste Dir da etwas fast ausschließlich C-artiges zusammengefrickelt hast (ohne ++).

    Wa sich auch sehr schade finde ist, dass Du im anderen Thread gewagt hast zu sagen "wenn du nicht weißt, was ein token ist, solltest du vielleicht gar nicht antworten" ohne selbst dabei nur den blassesten Schimmer zu haben. Mit solchen Inkompetenz-Demonstrationen disqualifiziert man sich ganz schnell und wird eher links liegen gelassen.

    Ich hatte an folgendes gedacht: Eine Funktion, die nachträglich in den string whitespacezeichen einfügt. Gibt es so etwas?

    Bsp: string = "2+2*2" , die Funktion würde dann nachträglich folgendes machen:
    string = "2 + 2 * 2". Dann würde nämlich auch die strtok() Funktion funzen.

    Und woher soll diese Funktion wissen, wo Leerzeichen eingefügt werden sollen? Muss sie dazu nicht schon wissen, wo "Tokens" anfangen und aufhören? Das Problem, Tokens zu identifizieren, besteht dann weiterhin.



  • Kann ich eigentlich auch den Inhalt einer Variable in den Eingabestream lesen?

    z.b.:

    int a = 2;
    a >> cin;
    

    oder einfach die Operatoren >> auch verwenden um Variablen untereinander zu verändern?

    Ich würde nämlich gerne an deinem Parser folgendes ändern:

    In der main() möchte ich,dass nicht aus "cin >> noskipws" sonder aus einer string variable in noskipws eingelesen wird:

    sting r = "2+2*2";
    r >> noskipws;
    

    Wie kann ich das erreichen?

    Gibt es da eine Möglichkeit?



  • Siehe std::stringstream und Konsorten.
    Vielleicht arbeitest Du erstmal Dein Buch weiter durch...



  • Golfi1812 schrieb:

    In der main() möchte ich,dass nicht aus "cin >> noskipws" sonder aus einer string variable in noskipws eingelesen wird:

    sting r = "2+2*2";
    r >> noskipws;
    

    Wie kann ich das erreichen?

    Gibt es da eine Möglichkeit?

    Hallo Golfi,

    genau das habe ich versucht, Dir hier zu erklären.

    Werner Salomon schrieb:

    Falls Du keinen std::istream hast, so schreibe den Text einfach in einen istringstream.

    std::string userEingabe = /* Dein Ding */;
        std::istringstream input( userEingabe );
        double val;
        if( input >> expression( val ) )
            // der Inhalt von 'val' enthält das Ergebnis
    

    siehe dazu auch das main() am Ende meines Listing, hinter dem Link oben.

    Setze einfach r gleich userEingabe . Du hast irgendwas nicht verstanden, ich weiß aber nicht was? 😕

    Gruß
    Werner



  • In welche Funktion muss ich das:

    std::string userEingabe = /* Dein Ding */; 
        std::istringstream input( userEingabe ); 
        double val; 
        if( input >> expression( val ) ) 
            // der Inhalt von 'val' enthält das Ergebnis
    

    einsetzen bzw. was muss ich damit ersetzen?



  • In Deine Funktion, da wo Du die Eingabe des Users zur Verfügung hast, und daraus den Wert der Eingabe bestimmen möchtest.

    string r = "2+2*2";
        string userEingabe = r; // Dein Ding
        istringstream input( userEingabe );
        double ergebnis;
        if( input >> expression( ergebnis ) )
        {
            // der Inhalt von 'ergebnis' enthält das Ergebnis; in diesem Fall von r="2+2*2" den Wert 6.0
    

    ich verstehe Dein Problem nicht 😕

    Gruß
    Werner


Log in to reply