Necesito cargar y usar los datos del archivo CSV en C ++. En este punto, realmente puede ser un analizador delimitado por comas (es decir, no se preocupe por escapar de nuevas líneas y comas). La necesidad principal 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.
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 muy difícil de depurar. Manténgase alejado deboost::spirit
si es posible.spirit
es bastante difícil de usar para una biblioteca de combinador de analizadores. Habiendo tenido una experiencia (muy agradable) con las(atto)parsec
bibliotecas de Haskells , esperaba que (espíritu) funcionara de manera similar, pero me di por vencido después de luchar con 600 errores de compilación de línea.Respuestas:
Si no le importa escapar de la coma y la nueva línea,
Y no puede insertar comas y nuevas
líneas entre comillas (Si no puede escapar, entonces ...), entonces solo se trata de tres líneas de código (OK 14 -> Pero es solo 15 para leer el archivo completo).
Simplemente crearía una clase que representa una fila.
Luego transmita a ese objeto:
Pero con un poco de trabajo podríamos crear técnicamente un iterador:
fuente
istream::operator>>
(como Eigen), agregue uninline
antes de la declaración del operador para solucionarlo.Solución usando Boost Tokenizer:
fuente
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:
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.
fuente
const char *vinit[] = {""}; vector<string> fields(vinit, end(vinit));
La biblioteca de C ++ String Toolkit (StrTk) tiene una clase de cuadrícula de token que le permite cargar datos desde archivos de texto, cadenas o buffers de caracteres , y analizarlos / procesarlos en una fila-columna.
Puede especificar los delimitadores de fila y delimitadores de columna o simplemente usar los valores predeterminados.
Más ejemplos se pueden encontrar aquí
fuente
options.trim_dquotes = true
), no admite la eliminación de comillas dobles (por ejemplo, el campo"She said ""oh no"", and left."
como la cadena c"She said \"oh no\", and left."
). Tendrás que hacerlo tú mismo.strtk
, también tendrá que manejar manualmente los campos con comillas dobles que contienen caracteres de nueva línea.Puede usar Boost Tokenizer con escaped_list_separator.
Esto solo usa los archivos de encabezado del tokenizer Boost, no se requieren enlaces para impulsar las bibliotecas.
Aquí hay un ejemplo, (vea Parse CSV File With Boost Tokenizer In C ++ para más detalles o
Boost::tokenizer
):fuente
No es excesivo usar Spirit para analizar CSV. Spirit es muy adecuado para tareas de micro-análisis. Por ejemplo, con Spirit 2.1, es tan fácil como:
El vector, v, se rellena con los valores. Hay una serie de tutoriales sobre esto en los nuevos documentos de Spirit 2.1 que se acaba de lanzar 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 para usar Spirit. El código generado es tan estricto como el código escrito a mano. ¡Mira el ensamblador generado!
fuente
Si HACES atención acerca de analizar CSV correctamente, esto lo hará ... con relativa lentitud, ya que funciona con un carácter a la vez.
fuente
Al usar el Boost Tokenizer escaped_list_separator para archivos CSV, uno debe tener en cuenta lo siguiente:
El formato CSV especificado por wiki establece que los campos de datos pueden contener separadores entre comillas (compatible):
El formato CSV especificado por wiki establece que las comillas simples deben manejarse con comillas dobles (escaped_list_separator eliminará todos los caracteres de comillas):
El formato CSV no especifica que se eliminen los caracteres de barra diagonal inversa (escaped_list_separator eliminará todos los caracteres de escape).
Una posible solución para corregir el comportamiento predeterminado del impulso escaped_list_separator:
Esta solución alternativa tiene el efecto secundario de que los campos de datos vacíos que están representados por una comilla doble se transformarán en un token de comillas simples. Al iterar a través de los tokens, uno debe verificar si el token es una comilla simple y tratarlo como una cadena vacía.
No es bonito, pero funciona, siempre que no haya nuevas líneas dentro de las comillas.
fuente
Es posible que desee ver mi proyecto CSVfix de FOSS ( enlace actualizado ), que es un editor de flujo CSV escrito en C ++. El analizador CSV no es un premio, pero hace el trabajo y todo el paquete puede hacer lo que necesita sin tener que escribir ningún código.
Consulte alib / src / a_csv.cpp para el analizador CSV y csvlib / src / csved_ioman.cpp (
IOManager::ReadCSV
) para ver un ejemplo de uso.fuente
Como todas las preguntas de CSV parecen ser redirigidas aquí, pensé en publicar mi respuesta aquí. Esta respuesta no aborda directamente la pregunta del autor de la pregunta. Quería poder leer en una secuencia que se sabe que está en formato CSV, y también los tipos de cada campo ya se conocían. Por supuesto, el siguiente método podría usarse para tratar cada campo como un tipo de cadena.
Como un ejemplo de cómo quería poder usar un flujo de entrada CSV, considere la siguiente entrada (tomada de la página de Wikipedia en CSV ):
Entonces, quería poder leer los datos de esta manera:
Esta fue la solución con la que terminé.
Con los siguientes ayudantes que pueden simplificarse con las nuevas plantillas de rasgos integrales en C ++ 11:
Pruébalo en línea!
fuente
Escribí un analizador CSV C ++ 11 de solo encabezado . Está bien probado, es rápido, admite toda la especificación CSV (campos entre comillas, delimitador / terminador en comillas, escape de comillas, etc.) y es configurable para dar cuenta de los CSV que no se adhieren a la especificación.
La configuración se realiza a través de una interfaz fluida:
El análisis es solo un rango basado en el bucle:
fuente
Aquí se puede encontrar otra biblioteca de E / S CSV:
http://code.google.com/p/fast-cpp-csv-parser/
fuente
Otra solución similar a la respuesta de Loki Astari , en C ++ 11. Las filas aquí son
std::tuple
s de un tipo dado. El código escanea una línea, luego escanea hasta cada delimitador y luego convierte y descarga el valor directamente en la tupla (con un poco de código de plantilla).Avances:
std::tuple<t1, ...>
viaoperator>>
.Lo que falta:
El código principal:
Puse un pequeño ejemplo de trabajo en GitHub ; Lo he estado usando para analizar algunos datos numéricos y cumplió su propósito.
fuente
Aquí hay otra implementación de un analizador CSV Unicode (funciona con wchar_t). Escribí parte de él, mientras Jonathan Leffler escribió el resto.
Nota: Este analizador tiene como objetivo replicar el comportamiento de Excel lo más cerca posible, específicamente al importar archivos CSV rotos o malformados .
Esta es la pregunta original: analizar el archivo CSV con campos multilínea y comillas dobles escapadas
Este es el código como un SSCCE (ejemplo corto, autocontenido, correcto).
fuente
Necesitaba una biblioteca C ++ fácil de usar para analizar archivos CSV, pero no pude encontrar ninguna disponible, así que terminé compilando una. Rapidcsv es una biblioteca de solo encabezado C ++ 11 que brinda acceso directo a columnas analizadas (o filas) como vectores, en el tipo de datos que elija. Por ejemplo:
fuente
Disculpe, pero todo esto parece una gran sintaxis elaborada para ocultar algunas líneas de código.
¿Por qué no esto?
fuente
",\n"
en la cadena?Aquí hay un código para leer una matriz, tenga en cuenta que también tiene una función csvwrite en matlab
fuente
Puede abrir y leer archivos .csv usando las funciones fopen, fscanf, pero lo importante es analizar los datos. La forma más sencilla de analizar los datos usando delimitador. En el caso de .csv, el delimitador es ','.
Suponga que su archivo data1.csv es el siguiente:
puede tokenizar datos y almacenarlos en una matriz de caracteres y luego usar la función atoi (), etc. para conversiones apropiadas
[^,], ^ -it invierte la lógica, significa hacer coincidir cualquier cadena que no contenga coma y luego la última, dice que coincide con la coma que terminó la cadena anterior.
fuente
Lo primero que debe hacer es asegurarse de que el archivo existe. Para lograr esto, solo necesita intentar abrir la secuencia de archivos en la ruta. Después de abrir la secuencia de archivos, use stream.fail () para ver si funcionó como se esperaba o no.
También debe verificar que el archivo proporcionado sea el tipo correcto de archivo. Para lograr esto, debe mirar a través de la ruta del archivo proporcionada hasta que encuentre la extensión del archivo. Una vez que tenga la extensión de archivo, asegúrese de que sea un archivo .csv.
Esta función devolverá la extensión de archivo que se usa más adelante en un mensaje de error.
Esta función realmente llamará a las verificaciones de error creadas anteriormente y luego analizará el archivo.
fuente
Tienes que sentirte orgulloso cuando usas algo tan hermoso como
boost::spirit
Aquí mi intento de un analizador (casi) que cumple con las especificaciones CSV en este enlace Especificaciones CSV (no necesitaba saltos de línea dentro de los campos. También se descartan los espacios alrededor de las comas).
Después de superar la impactante experiencia de esperar 10 segundos para compilar este código :), puede sentarse y disfrutar.
Compilar:
Prueba (ejemplo robado de Wikipedia ):
fuente
Esta solución detecta estos 4 casos.
la clase completa está a las
https://github.com/pedro-vicente/csv-parser
Lee el archivo carácter por carácter y lee 1 fila a la vez en un vector (de cadenas), por lo tanto, es adecuado para archivos muy grandes.
El uso es
Iterar hasta que se devuelva una fila vacía (final del archivo). Una fila es un vector donde cada entrada es una columna CSV.
la declaración de clase
la implementación
fuente
También puede echar un vistazo a las capacidades de la
Qt
biblioteca.Tiene soporte para expresiones regulares y la clase QString tiene buenos métodos, por ejemplo,
split()
devolver QStringList, la lista de cadenas obtenidas dividiendo la cadena original con un delimitador proporcionado. Debería ser suficiente para el archivo csv.Para obtener una columna con un nombre de encabezado dado, uso lo siguiente: c ++ herencia Qt problema qstring
fuente
Si no desea lidiar con la inclusión de impulso en su proyecto (es considerablemente grande si todo lo que va a usar es el análisis CSV ...)
He tenido suerte con el análisis CSV aquí:
http://www.zedwood.com/article/112/cpp-csv-parser
Maneja los campos entre comillas, pero no maneja los caracteres \ n en línea (lo que probablemente sea bueno para la mayoría de los usos).
fuente
Este es un hilo antiguo pero todavía está en la parte superior de los resultados de búsqueda, por lo que estoy agregando mi solución usando std :: stringstream y un método simple de reemplazo de cadena por Yves Baumes que encontré aquí.
El siguiente ejemplo leerá un archivo línea por línea, ignorará las líneas de comentarios que comienzan con // y analizará las otras líneas en una combinación de cadenas, ints y dobles. Stringstream realiza el análisis, pero espera que los campos estén delimitados por espacios en blanco, por lo que utilizo stringreplace para convertir las comas en espacios primero. Maneja las pestañas bien, pero no trata con cadenas citadas.
La entrada incorrecta o faltante simplemente se ignora, lo que puede o no ser bueno, dependiendo de su circunstancia.
fuente
Por lo que vale, aquí está mi implementación. Se ocupa de la entrada de wstring, pero podría ajustarse a la cadena fácilmente. No maneja la nueva línea en los campos (como mi aplicación tampoco lo hace, pero agregar su soporte no es demasiado difícil) y no cumple con el final de línea "\ r \ n" según RFC (suponiendo que use std :: getline), pero maneja el recorte de espacios en blanco y las comillas dobles correctamente (con suerte).
fuente
Aquí hay una función lista para usar si todo lo que necesita es cargar un archivo de datos de dobles (sin números enteros, sin texto).
fuente
Otra forma rápida y fácil es usar
Boost.Fusion I/O
:Salidas:
fuente
Escribí una buena manera de analizar archivos CSV y pensé que debería agregarlo como respuesta:
fuente
Es posible de usar
std::regex
.Dependiendo del tamaño de su archivo y la memoria disponible para usted, es posible leerlo línea por línea o completamente en un archivo
std::string
.Para leer el archivo se puede usar:
entonces puede combinar con esto, que en realidad es personalizable según sus necesidades.
fuente
Como no estoy acostumbrado a impulsar en este momento, sugeriré una solución más simple. Supongamos que su archivo .csv tiene 100 líneas con 10 números en cada línea separadas por un ','. Puede cargar estos datos en forma de matriz con el siguiente código:
fuente