¿Cómo puedo leer y analizar archivos CSV en C++?

9 minutos de lectura

¿Como puedo leer y analizar archivos CSV en C
Usuario1

Necesito cargar y usar datos de archivos CSV en C++. En este punto, puede ser simplemente un analizador delimitado por comas (es decir, no se preocupe por escapar de nuevas líneas y comas). La principal necesidad es un analizador línea por línea que devolverá un vector para la siguiente línea cada vez que se llame al método.

Encontré este artículo que parece bastante prometedor:
http://www.boost.org/doc/libs/1_35_0/libs/spirit/example/fundamental/list_parser.cpp

Nunca he usado Boost’s Spirit, pero estoy dispuesto a probarlo. Pero solo si no hay una solución más sencilla que estoy pasando por alto.

  • he mirado boost::spirit para analizar Es más para analizar gramáticas gracias a analizar un formato de archivo simple. Alguien en mi equipo estaba tratando de usarlo para analizar XML y fue complicado depurarlo. Alejate de boost::spirit si es posible.

    – Chris

    13 de julio de 2009 a las 19:30

  • Lo siento Chris, pero ese es un consejo terrible. Spirit no siempre es una solución adecuada, pero lo he usado, y sigo usándolo, con éxito en varios proyectos. En comparación con herramientas similares (Antlr, Lex/yacc, etc.), tiene ventajas significativas. Ahora, para analizar CSV es probablemente excesivo…

    – MattyT

    14 de julio de 2009 a las 12:09

  • @MattyT en mi humilde opinión spirit es bastante difícil de usar para una biblioteca de combinador de analizador. Habiendo tenido alguna experiencia (muy agradable) con Haskells (atto)parsec bibliotecas Esperaba que (espíritu) funcionara de manera similar, pero lo dejé después de luchar con 600 errores de compilación de línea.

    – fho

    14 de julio de 2014 a las 13:24

  • Analizador CSV C: sourceforge.net/projects/cccsvparser C CSV Escritor: sourceforge.net/projects/cccsvwriter

    – Algo algo

    23 de agosto de 2014 a las 21:22


  • ¿Por qué no quieres escapar de las comas y las nuevas líneas? ¡Todas las búsquedas enlazan con esta pregunta y no pude encontrar una respuesta que considere el escape! 😐

    – shhh

    18 mayo 2021 a las 15:58

¿Como puedo leer y analizar archivos CSV en C
Sastanín

Mi versión no usa nada más que la biblioteca estándar de C++ 11. Se adapta bien a la cita de Excel CSV:

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

El código está escrito como una máquina de estado finito y consume un carácter a la vez. Creo que es más fácil razonar.

#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;
}

  • este vector anidado de cadenas no funciona para los procesadores modernos. Tira a la basura su capacidad de almacenamiento en caché

    – Nikos Yotis

    5 de abril de 2018 a las 6:56

  • además, tienes todas esas declaraciones de cambio

    – Nikos Yotis

    5 de abril de 2018 a las 7:05

  • La respuesta principal no funcionó para mí, ya que estoy en un compilador más antiguo. Esta respuesta funcionó, la inicialización del vector puede requerir esto: const char *vinit[] = {""}; vector<string> fields(vinit, end(vinit));

    – dr_rk

    6 de abril de 2018 a las 9:16


  • Parece una gran solución y la mejor solución. Gracias. Creo que podría evitar usar el contador i usando el método en su vector llamado campos.

    – Marcas.

    9 de junio de 2021 a las 19:52

  • Solución muy limpia, esta es una mejor respuesta que la más alto responder !

    – jgx

    6 de agosto de 2021 a las 7:19

  • El tokenizador boost no es totalmente compatible con el estándar CSV completo, pero existen algunas soluciones rápidas. Consulte stackoverflow.com/questions/1120140/csv-parser-in-c/…

    –Rolf Kristensen

    13 de abril de 2010 a las 23:03

  • ¿Tiene que tener toda la biblioteca de impulso en su máquina, o puede simplemente usar un subconjunto de su código para hacer esto? 256 MB parece mucho para el análisis de CSV.

    – NPike

    27 de abril de 2011 a las 23:28

  • @NPike: puedes usar el bcp utilidad que viene con impulso para extraer solo los encabezados que realmente necesita.

    – ildjarn

    24 mayo 2011 a las 23:06

los Biblioteca de herramientas de cadenas de C++ (StrTk) tiene una clase de cuadrícula de token que le permite cargar datos desde archivos de texto, cadenas o búferes de caracteresy para analizarlos/procesarlos de forma fila-columna.

Puede especificar los delimitadores de fila y los delimitadores de columna o simplemente usar los valores predeterminados.

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;
}

Se pueden encontrar más ejemplos Aquí

  • Aunque strtk admite campos entre comillas doblese incluso eliminar las comillas circundantes (a través de options.trim_dquotes = true), no admite la eliminación de comillas dobles duplicadas (por ejemplo, el campo "She said ""oh no"", and left." como la cuerda c "She said \"oh no\", and left."). Tendrás que hacerlo tú mismo.

    – rampanion

    28 de agosto de 2017 a las 20:29


  • Cuando usas strtktambién deberá manejar manualmente los campos entre comillas dobles que contienen caracteres de nueva línea.

    – rampanion

    29 de agosto de 2017 a las 19:02

¿Como puedo leer y analizar archivos CSV en C
Zitrax

Puede usar Boost Tokenizer con escaped_list_separator.

separador_lista_escapada analiza un superconjunto del csv. Boost::tokenizador

Esto solo usa los archivos de encabezado del tokenizador Boost, no se requiere vinculación para impulsar las bibliotecas.

He aquí un ejemplo, (ver Analizar archivo CSV con Boost Tokenizer en C++ para detalles o 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;
    }
}

  • Aunque strtk admite campos entre comillas doblese incluso eliminar las comillas circundantes (a través de options.trim_dquotes = true), no admite la eliminación de comillas dobles duplicadas (por ejemplo, el campo "She said ""oh no"", and left." como la cuerda c "She said \"oh no\", and left."). Tendrás que hacerlo tú mismo.

    – rampanion

    28 de agosto de 2017 a las 20:29


  • Cuando usas strtktambién deberá manejar manualmente los campos entre comillas dobles que contienen caracteres de nueva línea.

    – rampanion

    29 de agosto de 2017 a las 19:02

1647659769 475 ¿Como puedo leer y analizar archivos CSV en C
foraidt

No es exagerado usar Spirit para analizar archivos CSV. Spirit es muy adecuado para tareas de microanálisis. Por ejemplo, con Spirit 2.1, es tan fácil como:

bool r = phrase_parse(first, last,

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

    space, v);

El vector, v, se rellena con los valores. Hay una serie de tutoriales. tocando esto en los nuevos documentos de Spirit 2.1 que acaban de ser lanzados con Boost 1.41.

El tutorial progresa de simple a complejo. Los analizadores CSV se presentan en algún lugar en el medio y tocan varias técnicas en el uso de Spirit. El código generado es tan estricto como el código escrito a mano. ¡Mira el ensamblador generado!

  • En realidad, es excesivo, el tiempo de compilación es enorme y hace que el uso de Spirit para simples “tareas de microanálisis” no sea razonable.

    – Gerdiner

    2 de diciembre de 2012 a las 0:37

  • También me gustaría señalar que el código anterior no analiza CSV, solo analiza un rango del tipo del vector delimitado por comas. No maneja comillas, diferentes tipos de columnas, etc. En resumen, 19 votos por algo que responde a la pregunta me parece un poco sospechoso.

    – Gerdiner

    2 de diciembre de 2012 a las 0:40

  • @Gerdiner Tonterías. El tiempo de compilación para los analizadores pequeños no es tan grande, pero también es irrelevante porque metes el código en su propia unidad de compilación y lo compilas. una vez. Entonces solo necesita vincularlo y eso es lo más eficiente posible. Y en cuanto a su otro comentario, hay tantos dialectos de CSV como procesadores para él. Este ciertamente no es un dialecto muy útil, pero puede extenderse de manera trivial para manejar valores entrecomillados.

    – Konrad Rodolfo

    6 de diciembre de 2012 a las 12:04


  • @konrad: simplemente incluir “#include ” en un archivo vacío con solo un principal y nada más toma 9.7 segundos con MSVC 2012 en un corei7 funcionando a 2.ghz. Es una hinchazón innecesaria. La respuesta aceptada se compila en menos de 2 segundos en la misma máquina, odiaría imaginar cuánto tiempo tomaría compilar el ejemplo ‘adecuado’ de Boost.Spirit.

    – Gerdiner

    11 de enero de 2013 a las 0:31

  • @Gerdiner Tengo que estar de acuerdo con usted en que la sobrecarga de usar espíritu para algo tan simple como el procesamiento de cvs es demasiado grande.

    usuario1781730

    25 de febrero de 2014 a las 0:48

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad