Preciso carregar e usar dados do arquivo CSV em C ++. Nesse ponto, ele pode realmente ser apenas um analisador delimitado por vírgula (ou seja, não se preocupe em escapar de novas linhas e vírgulas). A principal necessidade é um analisador de linha por linha que retornará um vetor para a próxima linha sempre que o método for chamado.
Encontrei este artigo que parece bastante promissor: http://www.boost.org/doc/libs/1_35_0/libs/spirit/example/fundamental/list_parser.cpp
Eu nunca usei o Boost's Spirit, mas estou disposto a tentar. Mas somente se não houver uma solução mais direta que eu esteja ignorando.
boost::spirit
para analisar. É mais para analisar gramáticas, graças à análise de um formato de arquivo simples. Alguém da minha equipe estava tentando usá-lo para analisar o XML e foi difícil depurar. Fique longe,boost::spirit
se possível.spirit
é bastante difícil de usar para uma biblioteca combinadora de analisadores. Tendo tido alguma experiência (muito agradável) com as(atto)parsec
bibliotecas Haskells, eu esperava que (espírito) funcionasse da mesma forma, mas desisti depois de lutar com erros do compilador de 600 linhas.Respostas:
Se você não se importa com a fuga de vírgula e nova linha,
E você não pode incorporar vírgula e nova linha entre aspas (se não puder escapar, então ...)
, são apenas três linhas de código (OK 14 -> Mas é apenas 15 para ler o arquivo inteiro).
Eu apenas criaria uma classe representando uma linha.
Em seguida, transmita para esse objeto:
Porém, com um pouco de trabalho, poderíamos criar tecnicamente um iterador:
fonte
istream::operator>>
(como Eigen), adicione umainline
declaração antes da operadora para corrigi-la.Solução usando o Boost Tokenizer:
fonte
Minha versão não está usando nada além da biblioteca C ++ 11 padrão. Ele lida bem com a cotação do Excel CSV:
O código é escrito como uma máquina de estado finito e consome um caractere por vez. Eu acho que é mais fácil argumentar.
fonte
const char *vinit[] = {""}; vector<string> fields(vinit, end(vinit));
A Biblioteca de C ++ String Toolkit (StrTk) possui uma classe de grade de tokens que permite carregar dados de arquivos de texto, seqüências de caracteres ou buffers de caractere e analisá-los / processá-los da maneira de coluna de linha.
Você pode especificar os delimitadores de linha e de coluna ou apenas usar os padrões.
Mais exemplos podem ser encontrados aqui
fonte
options.trim_dquotes = true
), ele não suporta a remoção de aspas duplas duplicadas (por exemplo, o campo"She said ""oh no"", and left."
como c-string"She said \"oh no\", and left."
). Você terá que fazer isso sozinho.strtk
, você também precisará manipular manualmente campos com aspas duplas que contenham caracteres de nova linha.Você pode usar o Boost Tokenizer com escaped_list_separator.
Isso usa apenas os arquivos de cabeçalho do tokenizer Boost, sem necessidade de vinculação para aumentar as bibliotecas.
Aqui está um exemplo (consulte Analisar arquivo CSV com o Boost Tokenizer no C ++ para obter detalhes ou
Boost::tokenizer
):fonte
Não é um exagero usar o Spirit para analisar CSVs. O Spirit é adequado para tarefas de micro-análise. Por exemplo, com o Spirit 2.1, é tão fácil quanto:
O vetor, v, é preenchido com os valores. Há uma série de tutoriais abordando isso nos novos documentos do Spirit 2.1 que foram lançados com o Boost 1.41.
O tutorial progride do simples ao complexo. Os analisadores de CSV são apresentados em algum lugar no meio e abordam várias técnicas no uso do Spirit. O código gerado é tão rígido quanto o código escrito à mão. Confira o assembler gerado!
fonte
Se você FAZER cuidado sobre como analisar CSV corretamente, isso vai fazê-lo ... de forma relativamente lenta, já que funciona um caractere de cada vez.
fonte
Ao usar o Boost Tokenizer escaped_list_separator para arquivos CSV, é necessário estar ciente do seguinte:
O formato CSV especificado pelo wiki afirma que os campos de dados podem conter separadores entre aspas (suportado):
O formato CSV especificado pelo wiki declara que aspas simples devem ser tratadas com aspas duplas (escaped_list_separator removerá todos os caracteres de aspas):
O formato CSV não especifica que nenhum caractere de barra invertida seja removido (escaped_list_separator removerá todos os caracteres de escape).
Uma possível solução alternativa para corrigir o comportamento padrão do impulso escaped_list_separator:
Essa solução alternativa tem o efeito colateral de que os campos de dados vazios representados por aspas duplas serão transformados em um token de aspas simples. Ao iterar pelos tokens, é necessário verificar se o token é de aspas simples e tratá-lo como uma string vazia.
Não é bonito, mas funciona, desde que não haja novas linhas entre aspas.
fonte
Você pode olhar para o meu projeto FOSS CSVfix ( link atualizado ), que é um editor de fluxo CSV escrito em C ++. O analisador de CSV não é um prêmio, mas faz o trabalho e todo o pacote pode fazer o que você precisa sem escrever nenhum código.
Consulte alib / src / a_csv.cpp para o analisador CSV e csvlib / src / csved_ioman.cpp (
IOManager::ReadCSV
) para obter um exemplo de uso.fonte
Como todas as perguntas sobre CSV parecem ser redirecionadas aqui, pensei em postar minha resposta aqui. Esta resposta não aborda diretamente a pergunta do solicitante. Queria poder ler em um fluxo conhecido por estar no formato CSV, e também os tipos de cada campo já eram conhecidos. Obviamente, o método abaixo poderia ser usado para tratar cada campo como um tipo de string.
Como um exemplo de como eu queria poder usar um fluxo de entrada CSV, considere a seguinte entrada (retirada da página da wikipedia em CSV ):
Então, eu queria poder ler os dados assim:
Esta foi a solução que eu acabei com.
Com os seguintes auxiliares que podem ser simplificados pelos novos modelos de características integrais no C ++ 11:
Experimente online!
fonte
Eu escrevi um analisador C ++ 11 CSV somente de cabeçalho . É bem testado, rápido, suporta toda a especificação CSV (campos entre aspas, delimitador / terminador entre aspas, escape de cotação etc.) e é configurável para contabilizar os CSVs que não aderem à especificação.
A configuração é feita através de uma interface fluente:
A análise é apenas um intervalo baseado em loop:
fonte
Outra biblioteca de E / S CSV pode ser encontrada aqui:
http://code.google.com/p/fast-cpp-csv-parser/
fonte
Outra solução semelhante à resposta de Loki Astari , em C ++ 11. Linhas aqui são
std::tuple
s de um determinado tipo. O código varre uma linha, depois varre até cada delimitador e, em seguida, converte e despeja o valor diretamente na tupla (com um pouco de código de modelo).Advanges:
std::tuple<t1, ...>
viaoperator>>
.O que está a faltar:
O código principal:
Eu coloquei um pequeno exemplo de trabalho no GitHub ; Eu tenho usado para analisar alguns dados numéricos e serviu a seu propósito.
fonte
Aqui está outra implementação de um analisador Unicode CSV (funciona com wchar_t). Eu escrevi parte, enquanto Jonathan Leffler escreveu o resto.
Nota: este analisador visa replicar o comportamento do Excel o mais próximo possível, especificamente ao importar arquivos CSV quebrados ou malformados .
Esta é a pergunta original - Analisando arquivo CSV com campos de múltiplas linhas e aspas duplas escapadas
Este é o código como um SSCCE (exemplo curto, independente e correto).
fonte
Eu precisava de uma biblioteca C ++ fácil de usar para analisar arquivos CSV, mas não consegui encontrar nenhum disponível, então acabei criando um. O Rapidcsv é uma biblioteca somente de cabeçalho C ++ 11 que fornece acesso direto a colunas (ou linhas) analisadas como vetores, no tipo de dados de sua escolha. Por exemplo:
fonte
Com licença, mas tudo isso parece uma grande sintaxe elaborada para ocultar algumas linhas de código.
Por que não isso:
fonte
",\n"
na corda?Aqui está o código para ler uma matriz, observe que você também tem uma função csvwrite no matlab
fonte
Você pode abrir e ler o arquivo .csv usando as funções fopen, fscanf, mas o importante é analisar os dados. A maneira mais simples de analisar os dados usando o delimitador. No caso de .csv, o delimitador é ','.
Suponha que seu arquivo data1.csv seja o seguinte:
você pode tokenizar dados e armazenar na matriz char e, posteriormente, usar a função atoi () etc para as conversões apropriadas
[^,], ^ - inverte a lógica, significa corresponder a qualquer sequência que não contenha vírgula e depois a última, diz corresponder à vírgula que terminou a sequência anterior.
fonte
A primeira coisa que você precisa fazer é garantir que o arquivo exista. Para fazer isso, basta tentar abrir o fluxo de arquivos no caminho. Depois de abrir o fluxo de arquivos, use stream.fail () para verificar se funcionou conforme o esperado ou não.
Você também deve verificar se o arquivo fornecido é o tipo correto de arquivo. Para fazer isso, você precisa examinar o caminho do arquivo fornecido até encontrar a extensão do arquivo. Depois de ter a extensão do arquivo, verifique se é um arquivo .csv.
Esta função retornará a extensão do arquivo que será usada posteriormente em uma mensagem de erro.
Essa função realmente chama as verificações de erro criadas acima e depois analisa o arquivo.
fonte
Você precisa se sentir orgulhoso quando usa algo tão bonito quanto
boost::spirit
Aqui, minha tentativa de um analisador (quase) em conformidade com as especificações CSV neste link Especificações CSV (eu não precisava de quebras de linha nos campos. Também os espaços ao redor das vírgulas são descartados).
Depois de superar a experiência chocante de esperar 10 segundos para compilar esse código :), você pode relaxar e aproveitar.
Compilar:
Teste (exemplo roubado da Wikipedia ):
fonte
Esta solução detecta esses 4 casos
aula completa é a
https://github.com/pedro-vicente/csv-parser
Ele lê o arquivo caractere por caractere e lê 1 linha por vez em um vetor (de seqüências de caracteres), portanto, adequado para arquivos muito grandes.
O uso é
Repita até que uma linha vazia seja retornada (final do arquivo). Uma linha é um vetor em que cada entrada é uma coluna CSV.
a declaração de classe
a implementação
fonte
Você também pode dar uma olhada nos recursos da
Qt
biblioteca.Ele possui suporte para expressões regulares e a classe QString possui métodos agradáveis, por exemplo,
split()
retornando QStringList, lista de strings obtidas dividindo a string original com um delimitador fornecido. Deve ser suficiente para o arquivo csv ..Para obter uma coluna com um nome de cabeçalho especificado, use o seguinte: herança c ++ Qt problem qstring
fonte
Se você não quiser lidar com a inclusão de aumento no seu projeto (é consideravelmente grande se tudo o que você vai usar para analisar CSV ...)
Eu tive sorte com o CSV analisando aqui:
http://www.zedwood.com/article/112/cpp-csv-parser
Ele lida com campos entre aspas - mas não lida com caracteres \ n embutidos (o que provavelmente é bom para a maioria dos usos).
fonte
Este é um tópico antigo, mas ainda está no topo dos resultados de pesquisa, por isso estou adicionando minha solução usando std :: stringstream e um método simples de substituição de string por Yves Baumes que encontrei aqui.
O exemplo a seguir lerá um arquivo linha por linha, ignorará as linhas de comentário iniciadas por // e analisará as outras linhas em uma combinação de cadeias, ints e duplas. Stringstream faz a análise, mas espera que os campos sejam delimitados por espaços em branco, então eu uso stringreplace para transformar vírgulas em espaços primeiro. Ele lida com guias ok, mas não lida com seqüências de caracteres citadas.
Entrada incorreta ou ausente é simplesmente ignorada, o que pode ou não ser bom, dependendo da sua circunstância.
fonte
Pelo que vale, aqui está a minha implementação. Ele lida com a entrada do wstring, mas pode ser ajustado facilmente para o string. Ele não lida com a nova linha nos campos (como meu aplicativo também não, mas adicionar seu suporte não é muito difícil) e não está em conformidade com o fim da linha "\ r \ n" conforme RFC (assumindo que você use std :: getline), mas lida com o recorte de espaço em branco e as aspas duplas corretamente (espero).
fonte
Aqui está uma função pronta para uso, se tudo o que você precisa é carregar um arquivo de dados com dobra (sem números inteiros, sem texto).
fonte
Outra maneira rápida e fácil é usar
Boost.Fusion I/O
:Saídas:
fonte
Eu escrevi uma ótima maneira de analisar arquivos CSV e achei que deveria adicioná-lo como resposta:
fonte
É possível usar
std::regex
.Dependendo do tamanho do seu arquivo e da memória disponível, é possível lê-lo linha por linha ou inteiramente em um arquivo
std::string
.Para ler o arquivo, pode-se usar:
então você pode combinar com isso, que é realmente personalizável para suas necessidades.
fonte
Como não estou acostumado a impulsionar agora, vou sugerir uma solução mais simples. Vamos supor que seu arquivo .csv tenha 100 linhas com 10 números em cada linha separados por um ','. Você pode carregar esses dados na forma de uma matriz com o seguinte código:
fonte