Ich muss CSV-Dateidaten in C ++ laden und verwenden. Zu diesem Zeitpunkt kann es sich wirklich nur um einen durch Kommas getrennten Parser handeln (dh Sie müssen sich keine Sorgen machen, dass neue Zeilen und Kommas entkommen). Der Hauptbedarf ist ein zeilenweiser Parser, der bei jedem Aufruf der Methode einen Vektor für die nächste Zeile zurückgibt.
Ich fand diesen Artikel ziemlich vielversprechend: http://www.boost.org/doc/libs/1_35_0/libs/spirit/example/fundamental/list_parser.cpp
Ich habe Boost's Spirit noch nie benutzt, bin aber bereit, es zu versuchen. Aber nur wenn es keine einfachere Lösung gibt, übersehe ich.
boost::spirit
Parsen gesucht . Es ist mehr für das Parsen von Grammatiken dank des Parsens eines einfachen Dateiformats. Jemand in meinem Team hat versucht, damit XML zu analysieren, und das Debuggen war mühsam. Halte dich fern,boost::spirit
wenn möglich.spirit
ist für eine Parser-Kombinator-Bibliothek ziemlich schwer zu verwenden. Nachdem ich einige (sehr angenehme) Erfahrungen mit Haskells-(atto)parsec
Bibliotheken gemacht hatte, erwartete ich, dass es (Spirit) ähnlich gut funktionieren würde, gab es aber auf, nachdem ich mit 600-Zeilen-Compiler-Fehlern gekämpft hatte.Antworten:
Wenn Sie sich nicht dafür interessieren, Komma und Zeilenumbruch zu maskieren,
UND Sie Komma und Zeilenumbruch nicht in Anführungszeichen einbetten können (wenn Sie dann nicht entkommen können ...),
dann sind es nur drei Codezeilen (OK 14 -> Aber es ist nur 15, um die ganze Datei zu lesen).
Ich würde nur eine Klasse erstellen, die eine Zeile darstellt.
Dann streame in dieses Objekt:
Aber mit ein wenig Arbeit könnten wir technisch einen Iterator erstellen:
quelle
istream::operator>>
(wie Eigen), fügen Sieinline
vor der Operator-Deklaration eine hinzu, um das Problem zu beheben.Lösung mit Boost Tokenizer:
quelle
Meine Version verwendet nur die Standard-C ++ 11-Bibliothek. Es kommt gut mit Excel CSV-Zitaten zurecht:
Der Code wird als Finite-State-Maschine geschrieben und verbraucht jeweils ein Zeichen. Ich denke, es ist einfacher, darüber nachzudenken.
quelle
const char *vinit[] = {""}; vector<string> fields(vinit, end(vinit));
Die C ++ String Toolkit Library (StrTk) verfügt über eine Token-Grid-Klasse, mit der Sie Daten entweder aus Textdateien, Zeichenfolgen oder Zeichenpuffern laden und zeilenspaltenweise analysieren / verarbeiten können.
Sie können die Zeilen- und Spaltenbegrenzer angeben oder einfach die Standardeinstellungen verwenden.
Weitere Beispiele finden Sie hier
quelle
options.trim_dquotes = true
Entfernen der umgebenden Anführungszeichen (via ) unterstützt, unterstützt es nicht das Entfernen doppelter doppelter Anführungszeichen (z. B. das Feld"She said ""oh no"", and left."
als C-Zeichenfolge"She said \"oh no\", and left."
). Das musst du selbst machen.strtk
müssen Sie auch Felder in doppelten Anführungszeichen, die Zeilenumbrüche enthalten, manuell verarbeiten.Sie können Boost Tokenizer mit Escape_list_separator verwenden.
Dies verwendet nur Boost-Tokenizer-Header-Dateien, keine Verknüpfung zu Boost-Bibliotheken erforderlich.
Hier ein Beispiel (siehe CSV-Datei mit Boost Tokenizer in C ++ analysieren für Details oder
Boost::tokenizer
):quelle
Es ist nicht übertrieben, Spirit zum Parsen von CSVs zu verwenden. Spirit eignet sich gut für Micro-Parsing-Aufgaben. Zum Beispiel ist es mit Spirit 2.1 so einfach wie:
Der Vektor v wird mit den Werten gefüllt. In den neuen Spirit 2.1-Dokumenten, die gerade mit Boost 1.41 veröffentlicht wurden, gibt es eine Reihe von Tutorials, die dies ansprechen.
Das Tutorial geht von einfach bis komplex. Die CSV-Parser werden irgendwo in der Mitte präsentiert und berühren verschiedene Techniken bei der Verwendung von Spirit. Der generierte Code ist so eng wie handgeschriebener Code. Schauen Sie sich den generierten Assembler an!
quelle
Wenn Sie DO kümmern sich um CSV richtig Parsen, das wird es tun ... relativ langsam , da es ein Zeichen zu einem Zeitpunkt arbeitet.
quelle
Wenn Sie den Boost Tokenizer entkommen_list_separator für CSV-Dateien verwenden, sollten Sie Folgendes beachten:
Das im Wiki angegebene CSV-Format besagt, dass Datenfelder Trennzeichen in Anführungszeichen enthalten können (unterstützt):
Das im Wiki angegebene CSV-Format besagt, dass einfache Anführungszeichen mit doppelten Anführungszeichen behandelt werden sollen (Escape_list_separator entfernt alle Anführungszeichen):
Das CSV-Format gibt nicht an, dass Back-Slash-Zeichen entfernt werden sollen (Escape_list_separator entfernt alle Escape-Zeichen).
Eine mögliche Problemumgehung, um das Standardverhalten des Boosts zu beheben. Escape_list_separator:
Diese Umgehung hat den Nebeneffekt, dass leere Datenfelder, die durch ein doppeltes Anführungszeichen dargestellt werden, in ein einfaches Anführungszeichen umgewandelt werden. Wenn Sie die Token durchlaufen, müssen Sie überprüfen, ob es sich bei dem Token um ein einfaches Anführungszeichen handelt, und es wie eine leere Zeichenfolge behandeln.
Nicht schön, aber es funktioniert, solange die Anführungszeichen keine Zeilenumbrüche enthalten.
quelle
Vielleicht möchten Sie sich mein FOSS-Projekt CSVfix ( aktualisierter Link ) ansehen, bei dem es sich um einen in C ++ geschriebenen CSV-Stream-Editor handelt. Der CSV-Parser ist kein Preis, erledigt aber die Aufgabe und das gesamte Paket kann das tun, was Sie benötigen, ohne dass Sie Code schreiben.
Ein Verwendungsbeispiel finden Sie in alib / src / a_csv.cpp für den CSV-Parser und in csvlib / src / csved_ioman.cpp (
IOManager::ReadCSV
).quelle
Da alle CSV-Fragen hier umgeleitet zu werden scheinen, dachte ich, ich würde meine Antwort hier posten. Diese Antwort geht nicht direkt auf die Frage des Fragestellers ein. Ich wollte in der Lage sein, einen Stream einzulesen, von dem bekannt ist, dass er im CSV-Format vorliegt, und auch die Typen der einzelnen Felder waren bereits bekannt. Natürlich kann die folgende Methode verwendet werden, um jedes Feld als Zeichenfolgentyp zu behandeln.
Betrachten Sie als Beispiel dafür, wie ich einen CSV-Eingabestream verwenden möchte, die folgende Eingabe (entnommen aus der Wikipedia-Seite zu CSV ):
Dann wollte ich die Daten folgendermaßen einlesen können:
Dies war die Lösung, mit der ich endete.
Mit den folgenden Hilfsprogrammen, die durch die neuen Vorlagen für integrale Merkmale in C ++ 11 vereinfacht werden können:
Probieren Sie es online aus!
quelle
Ich habe einen Nur-Header-C ++ 11-CSV-Parser geschrieben . Es ist gut getestet, schnell, unterstützt die gesamte CSV-Spezifikation (Felder in Anführungszeichen, Trennzeichen / Abschlusszeichen in Anführungszeichen, Anführungszeichen, Anführungszeichen usw.) und kann so konfiguriert werden, dass CSVs berücksichtigt werden, die nicht der Spezifikation entsprechen.
Die Konfiguration erfolgt über eine fließende Schnittstelle:
Das Parsen ist nur ein Bereich, der auf der Schleife basiert:
quelle
Eine weitere CSV-E / A-Bibliothek finden Sie hier:
http://code.google.com/p/fast-cpp-csv-parser/
quelle
Eine andere Lösung ähnlich der Antwort von Loki Astari in C ++ 11. Zeilen hier sind
std::tuple
s von einem bestimmten Typ. Der Code scannt eine Zeile, scannt dann bis zu jedem Trennzeichen und konvertiert den Wert dann direkt in das Tupel (mit etwas Vorlagencode) und gibt ihn aus.Fortschritte:
std::tuple<t1, ...>
viaoperator>>
.Was fehlt:
Der Hauptcode:
Ich habe ein kleines Arbeitsbeispiel auf GitHub gestellt . Ich habe es zum Parsen einiger numerischer Daten verwendet und es hat seinen Zweck erfüllt.
quelle
Hier ist eine weitere Implementierung eines Unicode-CSV-Parsers (funktioniert mit wchar_t). Ich habe einen Teil davon geschrieben, während Jonathan Leffler den Rest schrieb.
Hinweis: Dieser Parser zielt darauf ab, das Verhalten von Excel so genau wie möglich zu replizieren, insbesondere beim Importieren fehlerhafter oder fehlerhafter CSV-Dateien.
Dies ist die ursprüngliche Frage - Analysieren einer CSV-Datei mit mehrzeiligen Feldern und doppelten Anführungszeichen
Dies ist der Code als SSCCE (kurzes, eigenständiges, korrektes Beispiel).
quelle
Ich brauchte eine benutzerfreundliche C ++ - Bibliothek zum Parsen von CSV-Dateien, konnte aber keine finden und habe am Ende eine erstellt. Rapidcsv ist eine reine C ++ 11-Header-Bibliothek, die direkten Zugriff auf analysierte Spalten (oder Zeilen) als Vektoren im Datentyp Ihrer Wahl bietet. Zum Beispiel:
quelle
Entschuldigen Sie, aber das alles scheint eine Menge ausgefeilter Syntax zu sein, um ein paar Codezeilen zu verbergen.
Warum nicht das:
quelle
",\n"
in der Saite sein?Hier ist Code zum Lesen einer Matrix. Beachten Sie, dass Sie in matlab auch eine csvwrite-Funktion haben
quelle
Sie können die CSV-Datei mit den Funktionen fopen und fscanf öffnen und lesen. Wichtig ist jedoch, dass Sie die Daten analysieren. Einfachste Methode zum Analysieren der Daten mit dem Trennzeichen. Bei CSV ist das Trennzeichen ','.
Angenommen, Ihre Datei data1.csv lautet wie folgt:
Sie können Daten tokenisieren und im char-Array speichern und später die Funktion atoi () usw. für entsprechende Konvertierungen verwenden
[^,], ^ -it invertiert die Logik, bedeutet Übereinstimmung mit einer Zeichenfolge, die kein Komma enthält, und sagt zuletzt, dass das Komma übereinstimmt, das die vorherige Zeichenfolge beendet hat.
quelle
Als erstes müssen Sie sicherstellen, dass die Datei vorhanden ist. Um dies zu erreichen, müssen Sie nur versuchen, den Dateistream im Pfad zu öffnen. Nachdem Sie den Dateistream geöffnet haben, verwenden Sie stream.fail (), um festzustellen, ob er wie erwartet funktioniert hat oder nicht.
Sie müssen auch überprüfen, ob die bereitgestellte Datei den richtigen Dateityp hat. Um dies zu erreichen, müssen Sie den angegebenen Dateipfad durchsuchen, bis Sie die Dateierweiterung finden. Wenn Sie die Dateierweiterung haben, stellen Sie sicher, dass es sich um eine CSV-Datei handelt.
Diese Funktion gibt die Dateierweiterung zurück, die später in einer Fehlermeldung verwendet wird.
Diese Funktion ruft die oben erstellten Fehlerprüfungen auf und analysiert dann die Datei.
quelle
Du musst stolz sein, wenn du etwas so Schönes wie verwendest
boost::spirit
Hier mein Versuch eines Parsers, der (fast) den CSV-Spezifikationen auf diesem Link entspricht. CSV-Spezifikationen (ich brauchte keine Zeilenumbrüche innerhalb von Feldern. Auch die Leerzeichen um die Kommas werden verworfen).
Nachdem Sie die schockierende Erfahrung überwunden haben, 10 Sekunden auf das Kompilieren dieses Codes zu warten :), können Sie sich zurücklehnen und genießen.
Kompilieren:
Test (Beispiel aus Wikipedia gestohlen ):
quelle
Diese Lösung erkennt diese 4 Fälle
komplette Klasse ist bei
https://github.com/pedro-vicente/csv-parser
Es liest die Datei zeichenweise und liest jeweils 1 Zeile in einen Vektor (aus Zeichenfolgen), der daher für sehr große Dateien geeignet ist.
Verwendung ist
Iterieren Sie, bis eine leere Zeile zurückgegeben wird (Dateiende). Eine Zeile ist ein Vektor, bei dem jeder Eintrag eine CSV-Spalte ist.
die Klassendeklaration
die Umsetzung
quelle
Sie können sich auch die Funktionen der
Qt
Bibliothek ansehen .Es unterstützt reguläre Ausdrücke und die QString-Klasse verfügt über nützliche Methoden, z. B. die
split()
Rückgabe von QStringList, einer Liste von Zeichenfolgen, die durch Teilen der ursprünglichen Zeichenfolge mit einem bereitgestellten Trennzeichen erhalten werden. Sollte für CSV-Datei ausreichen ..Um eine Spalte mit einem bestimmten Headernamen zu erhalten, verwende ich Folgendes: c ++ Vererbung Qt Problem qstring
quelle
Wenn Sie sich nicht mit dem Einbeziehen von Boost in Ihr Projekt befassen möchten (es ist beträchtlich groß, wenn Sie es nur für CSV-Parsing verwenden möchten ...)
Ich hatte Glück mit der CSV-Analyse hier:
http://www.zedwood.com/article/112/cpp-csv-parser
Es behandelt Felder in Anführungszeichen, jedoch keine Inline-Zeichen \ n (was für die meisten Verwendungen wahrscheinlich in Ordnung ist).
quelle
Dies ist ein alter Thread, der jedoch immer noch ganz oben in den Suchergebnissen steht. Daher füge ich meine Lösung mit std :: stringstream und einer einfachen Methode zum Ersetzen von Zeichenfolgen von Yves Baumes hinzu, die ich hier gefunden habe.
Im folgenden Beispiel wird eine Datei zeilenweise gelesen, Kommentarzeilen, die mit // beginnen, ignoriert und die anderen Zeilen in eine Kombination aus Zeichenfolgen, Ints und Doubles analysiert. Stringstream führt die Analyse durch, erwartet jedoch, dass Felder durch Leerzeichen begrenzt werden. Daher verwende ich stringreplace, um Kommas zuerst in Leerzeichen umzuwandeln. Es behandelt Tabs in Ordnung, behandelt jedoch keine Zeichenfolgen in Anführungszeichen.
Schlechte oder fehlende Eingaben werden einfach ignoriert, was je nach Ihren Umständen gut oder schlecht sein kann.
quelle
Für das, was es wert ist, hier ist meine Implementierung. Es befasst sich mit der Eingabe von Zeichenfolgen, kann jedoch leicht an Zeichenfolgen angepasst werden. Es behandelt keine Zeilenumbrüche in Feldern (wie meine Anwendung auch nicht, aber das Hinzufügen der Unterstützung ist nicht allzu schwierig) und entspricht nicht dem Zeilenende "\ r \ n" gemäß RFC (vorausgesetzt, Sie verwenden std :: getline), aber es behandelt Leerzeichen und doppelte Anführungszeichen korrekt (hoffentlich).
quelle
Hier ist eine einsatzbereite Funktion, wenn Sie lediglich eine Datendatei mit Doppelwerten laden müssen (keine Ganzzahlen, kein Text).
quelle
Eine andere schnelle und einfache Möglichkeit ist die Verwendung von
Boost.Fusion I/O
:Ausgänge:
quelle
Ich habe eine gute Methode zum Parsen von CSV-Dateien geschrieben und dachte, ich sollte sie als Antwort hinzufügen:
quelle
Es ist möglich zu verwenden
std::regex
.Abhängig von der Größe Ihrer Datei und dem verfügbaren Speicher ist es möglich, sie zeilenweise oder vollständig in einer Datei zu lesen
std::string
.Um die Datei zu lesen, kann man verwenden:
dann können Sie mit diesem übereinstimmen, das tatsächlich an Ihre Bedürfnisse anpassbar ist.
quelle
Da ich momentan nicht an Boost gewöhnt bin, werde ich eine einfachere Lösung vorschlagen. Nehmen wir an, Ihre CSV-Datei enthält 100 Zeilen mit 10 Zahlen in jeder Zeile, die durch ein ',' getrennt sind. Sie können diese Daten in Form eines Arrays mit dem folgenden Code laden:
quelle