Wie erfasst man 0-2 Gruppen in C ++ regulären Ausdrücken und druckt sie aus?

Bearbeiten 3

Ich bin zum Good'ol-Parsing-Ansatz übergegangen, als ich mich an den regulären Ausdruck gehalten habe. Es stellte sich nicht als so schlimm heraus, da der Dateiinhalt sehr sauber getokenet und die Token in einer Schleife mit einem geparst werden könnensehr einfache Zustandsmaschine. Diejenigen, die dies überprüfen möchten, finden in Stackoverflow bei meiner anderen Frage einen Codeausschnitt, der dies mit Range-for-, Ifstream-Iteratoren und benutzerdefiniertem Stream-Tokenizer ausführtHier. Diese Techniken verringern die Komplexität eines benutzerdefinierten Parsers erheblich.

Ich möchte den Dateiinhalt im ersten Teil in Erfassungsgruppen von zwei und dann nur Zeile für Zeile tokenisieren. Ich habe gerne eine semi-funktionale Lösung, aber ich möchte lernen, wie man das besser macht. Das heißt, ohne "zusätzliche Verarbeitung", um meinen Mangel an Wissen mit Fanggruppen auszugleichen. Als nächstes einige Vorbemerkungen und am Ende eine genauere Frage (die Zeile

const std::regex expression("([^:]+?)(^:|$)");

... ist die, nach der ich in Kombination mit der Verarbeitung der Ergebnisse fragen möchte).

Die Dateien, die grundsätzlich so definiert sind:

definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
HOW TO INTERPRET THE FOLLOWING SECTION OF ROWS
[DATA ROW 1]
[DATA ROW 2]
...
[DATA ROW n]

Wobei jede der Datenzeilen aus einer bestimmten Anzahl von Ganzzahlen oder Gleitkommazahlen besteht, die durch Leerzeichen getrennt sind. Jede Reihe hat so viele Zahlen wie die anderen (z.B. könnte jede Reihe vier ganze Zahlen haben). Der "Interpretationsabschnitt" teilt dieses Format also im Grunde genommen im Klartext in einer Zeile mit.

Ich habe eine fast funktionierende Lösung, die solche Dateien wie folgt liest:

int main() 
{
    std::ifstream file("xyz", std::ios_base::in);
    if(file.good())
    {
        std::stringstream file_memory_buffer;
        file_memory_buffer << file.rdbuf();
        std::string str = file_memory_buffer.str(); 
        file.close();

        const std::regex expression("([^:]+?)(^:|$)");
        std::smatch result;

        const std::sregex_token_iterator end;       
        for(std::sregex_token_iterator i(str.begin(), str.end(), expression); i != end; ++i)
        {
            std::cout << (*i) << std::endl;
        }
    }

    return EXIT_SUCCESS;
}

Mit dem regulären Ausdruck definiertexpressiondruckt es jetzt die<value> Teile der Definitionsdatei, dann der Interpretationsteil und dann die Datenzeilen nacheinander. Wenn ich den regulären Ausdruck in ändere

"([^:]+?)(:|$)"

... es druckt alle Zeilen, die in Gruppen von einer markiert sind, fast so, wie ich es gerne hätte, aber wie tokenisiert man den ersten Teil in Zweiergruppen und den Rest Zeile für Zeile?

Hinweise, Code und Erklärungen sind ausdrücklich erwünscht. Vielen Dank.

BEARBEITEN:

Wie zu bemerkenTom Kerr bereits, aber einige zusätzliche Punkte, dies ist auch eine Probe oder Codierung von Kata, wenn Sie so wollen, um keinen benutzerdefinierten Parser zu schreiben, sondern um zu sehen, ob ich - oder wir könnten :-) - dies mit Regex erreichen. Ich weiß, dass Regex hier nicht das effizienteste ist, aber es spielt keine Rolle.

Was ich mir wünschen würde, wäre so etwas wie eine Liste mit Tupeln von Header-Informationen (Tupel der Größe 2), dann die INTERPRET-Zeile (Tupel der Größe 1), mit der ich eine Funktion auswählen könnte, was mit den Daten geschehen soll Linien (Tupel der Größe 1).

Ja, die Zeile "SO WIRD'S GEMACHT" ist in einer Reihe gut definierter Zeichenfolgen enthalten, und ich konnte von Anfang an Zeile für Zeile lesen und dabei Zeichenfolgen aufteilen, bis eine der INTERPRET-Zeilen erfüllt ist. Ich weiß, dass diese Regex-Lösung nicht die effizienteste Methode ist, sondern eher das Codieren von Kata, um mich dazu zu bringen, etwas anderes als Kunden-Parser zu schreiben ).

BEARBEITEN 2

Ich habe es geschafft, durch Ändern des Iteratortyps auf die Tupel (im Kontext dieser Frage) zuzugreifen

const std::sregex_iterator end;     
for(std::sregex_iterator i(str.begin(), str.end(), expression); i != end; ++i)
{
    std::cout << "0: " << (*i)[0] << std::endl;
    std::cout << "1: " << (*i)[1] << std::endl;
    std::cout << "2: " << (*i)[2] << std::endl;
    std::cout << "***" << std::endl;
}

Obwohl dies noch weit entfernt ist von dem, was ich gerne hätte, stimmt etwas nicht mit dem regulären Ausdruck, den ich versuche, zu verwenden. Auf jeden Fall hilft auch dieser neue Fund, eine andere Art von Iterator.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage