2016-12-07 1 views
0

Ich versuche, Kommentare, Leerzeilen und zusätzliche Leerzeichen in einer Textdatei zu entfernen, dann die verbleibenden Elemente zu tokenisieren. Jedes Token benötigt ein Leerzeichen davor und danach.Tokenize Elemente aus einer Textdatei durch Entfernen von Kommentaren, zusätzlichen Leerzeichen und Leerzeilen in C++

exampleFile.txt 
var 

/* declare variables */a1 , 
b2a ,  c, 

Hier ist, was ab jetzt funktioniert,

string line; //line: represents one line of text from file 
ifstream InputFile("exampleFile", ios::in); //read from exampleFile.txt 

//Remove comments 
while (InputFile && getline(InputFile, line, '\0')) 
{ 
    while (line.find("/*") != string::npos) 
    { 
     size_t Begin = line.find("/*"); 
     line.erase(Begin, (line.find("*/", Begin) - Begin) + 2); 
     // Start at Begin, erase from Begin to where */ is found 
    } 
} 

Dies entfernt Kommentare, aber ich kann nicht einen Weg, um herauszufinden, zu tokenize scheinen, während dies geschieht.

Also meine Fragen sind:

  • Ist es möglich, Kommentare, Leerzeichen und Leerzeilen zu entfernen und alle in dieser while-Anweisung tokenize?
  • Wie kann ich eine Funktion implementieren, die Leerzeichen zwischen jedem Token hinzufügt, bevor sie Token werden? Token wie c müssen als c und individuell erkannt werden.

Vielen Dank im Voraus für die Hilfe!

+1

Aus dem Thema: Speichern Sie eine Suche: 'while ((size_t Begin = line.find ("/* "))! = String :: npos)' – user4581301

+0

Off topic: Was passiert, wenn der Block Kommentar nicht auf der endet gleiche Linie? – user4581301

+1

Und noch ein Offthema: Denken Sie darüber nach, was passieren wird, wenn das Programm das/* in 'while (line.find ("/* ")! = String :: npos)' findet. – user4581301

Antwort

0

Wenn Sie Whitespace-Zeichen überspringen müssen und Sie sich nicht um neue Zeilen kümmern, empfehle ich, die Datei mit operator>> zu lesen. könnten Sie schreiben einfach:

std::string word; 
bool isComment = false; 
while(file >> word) 
{ 
    if (isInsideComment(word, isComment)) 
     continue; 

    // do processing of the tokens here 
    std::cout << word << std::endl; 
} 

Wo die Hilfsfunktion wie folgt umgesetzt werden könnten:

bool isInsideComment(std::string &word, bool &isComment) 
{ 
    const std::string tagStart = "/*"; 
    const std::string tagStop = "*/"; 

    // match start marker 
    if (std::equal(tagStart.rbegin(), tagStart.rend(), word.rbegin())) // ends with tagStart 
    { 
     isComment = true; 
     if (word == tagStart) 
      return true; 

     word = word.substr(0, word.find(tagStart)); 
     return false; 
    } 

    // match end marker 
    if (isComment) 
    { 
     if (std::equal(tagStop.begin(), tagStop.end(), word.begin())) // starts with tagStop 
     { 
      isComment = false; 
      word = word.substr(tagStop.size()); 
      return false; 
     } 

     return true; 
    } 

    return false; 
} 

Für Ihr Beispiel würde dies ausdrucken:

var 
a1 
, 
b2a 
, 
c, 

Die obige Logik sollte auch Handle mehrzeilige Kommentare, wenn Sie interessiert sind.

Bezeichnen Sie jedoch, dass die Funktionsimplementierung entsprechend Ihren Annahmen bezüglich der Kommentartokens geändert werden sollte. Zum Beispiel sind sie immer mit Leerzeichen von anderen words getrennt? Oder ist es möglich, dass ein var1/*comment*/var2 Ausdruck analysiert würde? Das obige Beispiel funktioniert in einer solchen Situation nicht.

Daher wäre ein weitere Option sein (was Sie bereits begonnen Umsetzung) Lesezeilen oder sogar Stücke von Daten aus der Datei (um sicherzustellen, beginnt und endet Kommentar Token werden angepasst) und Lern ​​Positionen der Kommentarmarkierungen mit find oder regex zu Entferne sie danach.

+0

Ich verstehe, das ist hilfreich! Vielen Dank! –

+0

'line == tagStart' fängt nur die gesamte Zeichenfolge ab. Beim Lesen einer Zeile aus der Datei wird die Zeile auf die gesamte Zeile gesetzt. Also muss ich einen Teil der Zeichenkette mit "/ *" oder "* /" vergleichen, indem ich die gleiche Zeile [i] + Zeile [i + 1] verwende, aber das bringt mich dazu, Fehler zu schreiben. –

+0

Nicht sicher, ob ich dich richtig verstanden habe. Um Verwechslungen zu vermeiden, habe ich den Variablennamen 'line' auf' word' aktualisiert, da dies der Inhalt ist (nicht die Dateizeile im Allgemeinen). Wenn Sie Fälle wie 'var/* comment */var' behandeln müssen, habe ich auch die Funktion aktualisiert, um' std :: equal' zu verwenden. Aber wie ich geschrieben habe, ist dies eine allgemeine Idee und sollte an Ihre spezifischen Bedürfnisse angepasst werden. Es gibt wahrscheinlich mehr Details, die Sie nicht in der Frage geteilt haben, die Implementierungsaktualisierungen erfordern würden. – Dusteh

Verwandte Themen