2009-03-05 21 views
1

Ich habe eine große Reihe von Protokollzeilen und ich muss jede Zeile analysieren (so Effizienz ist sehr wichtig).Parsing einer Zeichenfolge in C++

Jede Protokollzeile ist von der Form

cust_name TIME_START TIME_END (IP oder URL) *

So IP-Adresse, Zeit, Zeit und eine möglicherweise leere Liste von IP-Adressen oder durch ein Semikolon getrennt Urls. Wenn in der letzten Liste nur IP oder URL vorhanden ist, gibt es kein Trennzeichen. Wenn dort mehr als 1 ist, dann werden sie durch Semikolons getrennt.

Ich brauche eine Möglichkeit, diese Zeile zu analysieren und in eine Datenstruktur zu lesen. time_start oder time_end könnte entweder Systemzeit oder GMT sein. cust_name könnte auch mehrere Zeichenfolgen haben, die durch Leerzeichen getrennt sind.

Ich kann dies tun, indem ich Zeichen für Zeichen lese und im Wesentlichen meinen eigenen Parser schreibe. Gibt es einen besseren Weg, dies zu tun?

+0

Hmmm ... können Sie garantieren, dass Semikolons nicht in Ihren URLs erscheinen? Oder zumindest, dass sie nicht an seinen Enden erscheinen? – dmckee

+0

Was ist Ihr Ziel? Was werden Sie nach der Analyse mit den Daten machen? – hasen

Antwort

1

Benutzerdefinierte Eingabe erfordert benutzerdefinierten Parser. Oder bete, dass es eine ideale Welt gibt und Fehler nicht existieren. Vor allem, wenn Sie Effizienz haben wollen. Das Posten von Code kann hilfreich sein.

0

Sie könnten versuchen, ein einfaches lex/yacc | flex/bison-Vokabular zu verwenden, um diese Art von Eingabe zu analysieren.

3

Warum wollen Sie diese in C++ zu tun? Es klingt wie ein offensichtlicher Job für etwas wie Perl.

+0

Sicher. Wenn er nur diesen Job macht. Aber der Kontext könnte ein existierender Code mit einer anderen primären Aufgabe sein ... – dmckee

+0

Er ist an der Leistung interessiert, und ein benutzerdefinierter C++ - Parser wird die Türen eines Perl-Parsers für die Geschwindigkeit der Ausführung (aber * nicht * Geschwindigkeit der Entwicklung) sprengen. –

+0

David, das stimmt nicht unbedingt. Es kann sehr leicht auf ihn (in Bezug auf die Leistung) zurückschlagen, wenn er die resultierende gigantische Datenstruktur im Speicher speichert! C++ wird da nicht helfen. – hasen

5

Ich hatte Erfolg mit Boost Tokenizer für diese Art von Sache. Es hilft Ihnen, einen Eingabestream in Tokens mit benutzerdefinierten Trennzeichen zwischen den Token zu brechen.

4

Verwenden von regulären Ausdrücken (boost::regex ist eine nette Implementierung für C++) verwenden können, können Sie einfach verschiedene Teile Ihrer Zeichenfolge trennen - cust_name, time_start ... und alle finden, dass urls \ ips

Zweiter Schritt ist eine detailliertere Analyse dieser Gruppen, falls erforderlich. Daten können zum Beispiel mit der Bibliothek boost::datetime analysiert werden (Schreiben eines benutzerdefinierten Parsers, wenn das Zeichenfolgenformat nicht Standard ist).

1

UPDATE änderte die Antwort drastisch!

Ich habe eine riesige Reihe von Protokollzeilen und ich muss jede Zeile analysieren (Effizienz ist also sehr wichtig).

Denken Sie nur daran, dass C++ in dieser Situation nicht viel zur Effizienz beitragen wird. Lassen Sie sich nicht dazu verleiten, zu denken, dass Ihr Programm eine hohe Performance hat, nur weil Sie in C++ einen schnellen Parsing-Code haben!

Die Effizienz, die Sie wirklich brauchen, ist nicht die Leistung auf der Ebene "Maschinencode" des Parsing-Codes, sondern auf der Ebene des gesamten Algorithmus.

Denken Sie darüber nach, was Sie zu tun versuchen.
Sie haben eine große Textdatei, und Sie mögen jede Zeile in eine Datenstruktur konvertieren,

Speicher große Datenstruktur im Speicher ist sehr ineffizient , egal welche Sprache Sie verwenden!

Was Sie tun müssen, ist "fetch" eine Zeile zu einer Zeit, konvertieren Sie es in eine Datenstruktur, und damit umgehen, dann, und nur nachdem Sie mit der Datenstruktur fertig sind, gehen Sie und holen Sie die nächste Zeile und konvertieren Sie es in eine Datenstruktur, damit umgehen, und wiederholen.

Wenn Sie das tun, haben Sie bereits den größten Engpass gelöst.

Für die Textzeile Parsen, es scheint, das Format Ihrer Daten ganz simpel ist, überprüfen Sie eine ähnliche Frage, die ich vor einiger Zeit gefragt: C++ string parsing (python style)

In Ihrem Fall, ich nehme an, Sie eine Zeichenfolge verwenden könnten streamen und den Operator >> verwenden, um das nächste "Ding" in der Zeile zu lesen.

siehe this answer zum Beispiel Code.

Alternativ (Ich wollte diesen Teil nicht löschen !!) Wenn Sie dies in Python schreiben könnten, wird es viel einfacher. Ich weiß nicht, Ihre Situation (es scheint, dass Sie mit C stecken ++), aber immer noch

Schauen Sie sich diese Präsentation für diese Art von Aufgabe zu tun Python-Generator Ausdrücke effizient zu nutzen: http://www.dabeaz.com/generators/Generators.pdf

Es ist ein Wert, während Lese . Auf Folie 31 beschäftigt er sich mit etwas, das dem, was Sie versuchen, sehr ähnlich zu sein scheint.

Es wird Ihnen zumindest einige Anregungen geben.
Es zeigt auch ziemlich stark, dass die Leistung nicht durch den bestimmten String-Parsing-Code, sondern den Overall-Algorithmus gewonnen wird.

+0

Ich denke, dass Sie eine gute Idee (eine Zeile zu einer Zeit) mit einer zusammenfügen, die vom Kontext abhängt (verwenden Sie nicht C++ dafür). Außerdem bemerkt das OP in den Kommentaren zu einer anderen Antwort, dass er dies in einem existierenden C++ Code macht. Nichtsdestoweniger +1 für den Punkt nach dem anderen. – dmckee

+0

guter Punkt! Ich habe die Antwort geändert. Aber zu meiner Verteidigung erwähnte er die bestehende C++ - App eine ganze Weile, nachdem ich meine Antwort veröffentlicht hatte – hasen

0

Der Parser, den Sie brauchen, klingt wirklich einfach. Take a look at this. Jede kompilierte Sprache sollte in der Lage sein, es mit sehr hoher Geschwindigkeit zu analysieren. Dann ist es ein Problem, welche Datenstruktur Sie erstellen & speichern.