Wie kann ich CSV-Dateien in C++ lesen und analysieren?

Lesezeit: 8 Minuten

Wie kann ich CSV Dateien in C lesen und analysieren
Benutzer1

Ich muss CSV-Dateidaten in C++ laden und verwenden. An dieser Stelle kann es sich wirklich nur um einen kommagetrennten Parser handeln (dh machen Sie sich keine Gedanken über das Escapezeichen für neue Zeilen und Kommas). Die Hauptanforderung ist ein zeilenweiser Parser, der bei jedem Aufruf der Methode einen Vektor für die nächste Zeile zurückgibt.

Ich habe diesen Artikel gefunden, der sehr vielversprechend aussieht:
http://www.boost.org/doc/libs/1_35_0/libs/spirit/example/fundamental/list_parser.cpp

Ich habe Boost’s Spirit noch nie verwendet, bin aber bereit, es zu versuchen. Aber nur, wenn es keine einfachere Lösung gibt, die ich übersehe.

  • habe ich angeschaut boost::spirit zum parsen. Es dient eher zum Parsen von Grammatiken als zum Parsen eines einfachen Dateiformats. Jemand in meinem Team hat versucht, damit XML zu parsen, und das Debuggen war mühsam. Bleiben Sie weg von boost::spirit wenn möglich.

    – chris

    13. Juli 2009 um 19:30 Uhr

  • Tut mir leid, Chrish, aber das ist ein schrecklicher Rat. Spirit ist nicht immer eine geeignete Lösung, aber ich habe es in einer Reihe von Projekten erfolgreich eingesetzt und nutze es weiterhin. Im Vergleich zu ähnlichen Tools (Antlr, Lex/yacc usw.) hat es erhebliche Vorteile. Nun, zum Analysieren von CSV ist es wahrscheinlich übertrieben …

    – MattyT

    14. Juli 2009 um 12:09 Uhr

  • @MattyT IMHO spirit ist ziemlich schwer für eine Parser-Kombinator-Bibliothek zu verwenden. Ich habe einige (sehr angenehme) Erfahrungen mit Haskells gemacht (atto)parsec Bibliotheken Ich hatte erwartet, dass es (spirit) ähnlich gut funktionieren würde, habe es aber aufgegeben, nachdem ich mit 600-Zeilen-Compilerfehlern gekämpft hatte.

    – fho

    14. Juli 2014 um 13:24 Uhr

  • C CSV-Parser: sourceforge.net/projects/cccsvparser C CSV-Writer: sourceforge.net/projects/cccsvwriter

    – Etwas etwas

    23. August 2014 um 21:22 Uhr


  • Warum wollen Sie Kommas und Zeilenumbrüchen nicht entkommen! Jede Suche verweist auf diese Frage und ich konnte keine Antwort finden, die das Entkommen berücksichtigt! 😐

    – Pssst

    18. Mai 2021 um 15:58 Uhr

Wie kann ich CSV Dateien in C lesen und analysieren
sastanin

Meine Version verwendet nichts anderes als die Standard-C++11-Bibliothek. Es kommt gut mit Excel CSV-Zitaten zurecht:

spam eggs,"foo,bar","""fizz buzz"""
1.23,4.567,-8.00E+09

Der Code ist als endlicher Automat geschrieben und verbraucht jeweils ein Zeichen. Ich denke, es ist einfacher, darüber nachzudenken.

#include <istream>
#include <string>
#include <vector>

enum class CSVState {
    UnquotedField,
    QuotedField,
    QuotedQuote
};

std::vector<std::string> readCSVRow(const std::string &row) {
    CSVState state = CSVState::UnquotedField;
    std::vector<std::string> fields {""};
    size_t i = 0; // index of the current field
    for (char c : row) {
        switch (state) {
            case CSVState::UnquotedField:
                switch (c) {
                    case ',': // end of field
                              fields.push_back(""); i++;
                              break;
                    case '"': state = CSVState::QuotedField;
                              break;
                    default:  fields[i].push_back(c);
                              break; }
                break;
            case CSVState::QuotedField:
                switch (c) {
                    case '"': state = CSVState::QuotedQuote;
                              break;
                    default:  fields[i].push_back(c);
                              break; }
                break;
            case CSVState::QuotedQuote:
                switch (c) {
                    case ',': // , after closing quote
                              fields.push_back(""); i++;
                              state = CSVState::UnquotedField;
                              break;
                    case '"': // "" -> "
                              fields[i].push_back('"');
                              state = CSVState::QuotedField;
                              break;
                    default:  // end of quote
                              state = CSVState::UnquotedField;
                              break; }
                break;
        }
    }
    return fields;
}

/// Read CSV file, Excel dialect. Accept "quoted fields ""with quotes"""
std::vector<std::vector<std::string>> readCSV(std::istream &in) {
    std::vector<std::vector<std::string>> table;
    std::string row;
    while (!in.eof()) {
        std::getline(in, row);
        if (in.bad() || in.fail()) {
            break;
        }
        auto fields = readCSVRow(row);
        table.push_back(fields);
    }
    return table;
}

  • Dieser verschachtelte Vektor von Strings ist für moderne Prozessoren ein No-Go. Wirft ihre Caching-Fähigkeit weg

    – Nikos Yotis

    5. April 2018 um 6:56 Uhr

  • Außerdem haben Sie all diese Switch-Anweisungen

    – Nikos Yotis

    5. April 2018 um 7:05 Uhr

  • Die oberste Antwort hat bei mir nicht funktioniert, da ich mich auf einem älteren Compiler befinde. Diese Antwort hat funktioniert, die Vektorinitialisierung erfordert möglicherweise Folgendes: const char *vinit[] = {""}; vector<string> fields(vinit, end(vinit));

    – dr_rk

    6. April 2018 um 9:16 Uhr


  • Sieht nach einer großartigen Lösung und der besten Lösung aus. Danke. Ich denke, dass Sie die Verwendung des Zählers i vermeiden könnten, indem Sie die Methode zurück auf Ihren Vektor namens Felder anwenden.

    – Markus S.

    9. Juni 2021 um 19:52 Uhr

  • Sehr saubere Lösung, das ist eine bessere Antwort als die oberste Antworten !

    – jgx

    6. August 2021 um 7:19 Uhr

  • Der Boost-Tokenizer unterstützt den vollständigen CSV-Standard nicht vollständig, aber es gibt einige schnelle Problemumgehungen. Siehe stackoverflow.com/questions/1120140/csv-parser-in-c/…

    – Rolf Kristensen

    13. April 2010 um 23:03 Uhr

  • Müssen Sie die gesamte Boost-Bibliothek auf Ihrem Computer haben, oder können Sie dafür nur eine Teilmenge ihres Codes verwenden? 256 MB scheinen viel für das CSV-Parsing zu sein.

    – NPike

    27. April 2011 um 23:28 Uhr

  • @NPike: Sie können die verwenden bcp Dienstprogramm, das mit Boost geliefert wird, um nur die Header zu extrahieren, die Sie tatsächlich benötigen.

    – Ildjarn

    24. Mai 2011 um 23:06 Uhr

Die C++-String-Toolkit-Bibliothek (StrTk) verfügt über eine Token-Grid-Klasse, mit der Sie Daten entweder aus laden können Textdateien, Zeichenketten oder Zeichenpufferund um sie zeilenweise zu analysieren/verarbeiten.

Sie können die Zeilen- und Spaltentrennzeichen angeben oder einfach die Standardwerte verwenden.

void foo()
{
   std::string data = "1,2,3,4,5\n"
                      "0,2,4,6,8\n"
                      "1,3,5,7,9\n";

   strtk::token_grid grid(data,data.size(),",");

   for(std::size_t i = 0; i < grid.row_count(); ++i)
   {
      strtk::token_grid::row_type r = grid.row(i);
      for(std::size_t j = 0; j < r.size(); ++j)
      {
         std::cout << r.get<int>(j) << "\t";
      }
      std::cout << std::endl;
   }
   std::cout << std::endl;
}

Weitere Beispiele sind zu finden Hier

  • Obwohl strtk unterstützt Felder in doppelten Anführungszeichenund sogar die umgebenden Anführungszeichen entfernen (via options.trim_dquotes = true), unterstützt es nicht das Entfernen doppelter Anführungszeichen (z. B. das Feld field "She said ""oh no"", and left." als C-Saite "She said \"oh no\", and left."). Das musst du selbst machen.

    – Rapunzel

    28. August 2017 um 20:29 Uhr


  • Beim Benutzen strtkmüssen Sie auch Felder in doppelten Anführungszeichen manuell behandeln, die Zeilenumbruchzeichen enthalten.

    – Rapunzel

    29. August 2017 um 19:02 Uhr

Wie kann ich CSV Dateien in C lesen und analysieren
Zitrax

Sie können Boost Tokenizer mit escaped_list_separator verwenden.

escaped_list_separator analysiert eine Obermenge der csv. Boost::tokenizer

Dies verwendet nur Boost-Tokenizer-Header-Dateien, es ist keine Verknüpfung mit Boost-Bibliotheken erforderlich.

Hier ein Beispiel (vgl Analysieren Sie die CSV-Datei mit Boost Tokenizer in C++ für Details bzw Boost::tokenizer ):

#include <iostream>     // cout, endl
#include <fstream>      // fstream
#include <vector>
#include <string>
#include <algorithm>    // copy
#include <iterator>     // ostream_operator
#include <boost/tokenizer.hpp>

int main()
{
    using namespace std;
    using namespace boost;
    string data("data.csv");

    ifstream in(data.c_str());
    if (!in.is_open()) return 1;

    typedef tokenizer< escaped_list_separator<char> > Tokenizer;
    vector< string > vec;
    string line;

    while (getline(in,line))
    {
        Tokenizer tok(line);
        vec.assign(tok.begin(),tok.end());

        // vector now contains strings from one row, output to cout here
        copy(vec.begin(), vec.end(), ostream_iterator<string>(cout, "|"));

        cout << "\n----------------------" << endl;
    }
}

  • Obwohl strtk unterstützt Felder in doppelten Anführungszeichenund sogar die umgebenden Anführungszeichen entfernen (via options.trim_dquotes = true), unterstützt es nicht das Entfernen doppelter Anführungszeichen (z. B. das Feld field "She said ""oh no"", and left." als C-Saite "She said \"oh no\", and left."). Das musst du selbst machen.

    – Rapunzel

    28. August 2017 um 20:29 Uhr


  • Beim Benutzen strtkmüssen Sie auch Felder in doppelten Anführungszeichen manuell behandeln, die Zeilenumbruchzeichen enthalten.

    – Rapunzel

    29. August 2017 um 19:02 Uhr

1647302417 355 Wie kann ich CSV Dateien in C lesen und analysieren
foraidt

Es ist nicht übertrieben, Spirit zum Parsen von CSVs zu verwenden. Spirit eignet sich gut für Micro-Parsing-Aufgaben. Mit Spirit 2.1 ist es beispielsweise so einfach wie:

bool r = phrase_parse(first, last,

    //  Begin grammar
    (
        double_ % ','
    )
    ,
    //  End grammar

    space, v);

Der Vektor v wird mit den Werten gefüllt. Es gibt eine Reihe von Tutorials Dies wird in der neuen Spirit 2.1-Dokumentation angesprochen, die gerade mit Boost 1.41 veröffentlicht wurde.

Das Tutorial geht von einfach bis komplex. Die CSV-Parser werden irgendwo in der Mitte vorgestellt und berühren verschiedene Techniken bei der Verwendung von Spirit. Der generierte Code ist so eng wie handgeschriebener Code. Sehen Sie sich den generierten Assembler an!

  • Eigentlich ist es übertrieben, die Kompilierungszeit ist enorm und macht die Verwendung von Spirit für einfache “Mikro-Parsing-Aufgaben” unvernünftig.

    – Gerdiner

    2. Dezember 2012 um 0:37 Uhr

  • Außerdem möchte ich darauf hinweisen, dass der obige Code CSV nicht analysiert, sondern nur einen Bereich des Typs des Vektors, der durch Kommas getrennt ist. Es verarbeitet keine Anführungszeichen, unterschiedliche Arten von Spalten usw. Kurz gesagt, 19 Stimmen für etwas, das die Frage überhaupt beantwortet, erscheint mir etwas verdächtig.

    – Gerdiner

    2. Dezember 2012 um 0:40 Uhr

  • @Gerdiner Unsinn. Der Kompilierungszeit-Hit für kleine Parser ist nicht so groß, aber auch irrelevant, weil Sie den Code in eine eigene Kompilierungseinheit stopfen und kompilieren Einmal. Dann brauchen Sie es nur noch zu verknüpfen und das ist so effizient wie es nur geht. Und was Ihren anderen Kommentar betrifft, gibt es so viele CSV-Dialekte wie es Prozessoren dafür gibt. Dies ist sicherlich kein sehr nützlicher Dialekt, aber er kann trivial erweitert werden, um Werte in Anführungszeichen zu verarbeiten.

    – Konrad Rudolf

    6. Dezember 2012 um 12:04 Uhr


  • @konrad: Das einfache Einfügen von “#include ” in eine leere Datei mit nur einer Hauptdatei und nichts anderem dauert mit MSVC 2012 auf einem Corei7 mit 2 GHz 9,7 Sekunden. Es ist unnötiges Aufblähen. Die akzeptierte Antwort wird auf demselben Computer in weniger als 2 Sekunden kompiliert. Ich möchte mir nur ungern vorstellen, wie lange das Kompilieren des „richtigen“ Boost.Spirit-Beispiels dauern würde.

    – Gerdiner

    11. Januar 2013 um 0:31 Uhr

  • @Gerdiner Ich muss Ihnen zustimmen, dass der Aufwand für die Verwendung von Spirit für etwas so Einfaches wie die CVS-Verarbeitung viel zu groß ist.

    Benutzer1781730

    25. Februar 2014 um 0:48 Uhr

1003440cookie-checkWie kann ich CSV-Dateien in C++ lesen und analysieren?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy