Trabalho com CSV em C++: do parsing manual à biblioteca libcsv
O formato CSV (Comma-Separated Values) continua sendo uma das formas mais populares de troca de dados tabulares. Em C++ não há suporte embutido para CSV, mas existem várias abordagens eficientes: parsing manual usando ferramentas padrão e bibliotecas especializadas, como libcsv. Neste artigo, abordaremos ambos os métodos, suas vantagens e desvantagens, além de fornecer exemplos de código funcionais.
O que é CSV e suas características
CSV é um formato de texto onde cada linha corresponde a um registro e os campos são separados por vírgulas. As principais dificuldades são:
- Os campos podem conter vírgulas se estiverem entre aspas (
"Olá, mundo"); - Aspas dentro do campo são escapadas por duplicação (
""); - O separador pode ser outro caractere (ponto e vírgula, tabulação);
- As linhas podem conter caracteres de nova linha dentro das aspas.
Portanto, simplesmente dividir a string por vírgulas geralmente leva a erros. Vamos considerar duas maneiras confiáveis.
Método 1: Parsing manual com std::stringstream
Adequado para CSVs simples sem aspas aninhadas ou quebras de linha. A implementação consiste em duas funções: leitura de um campo e análise de toda a linha.
#include <iostream>#include <fstream>#include <sstream>#include <vector>#include <string>
// Divisão de uma linha CSV em campos considerando aspasstd::vector<std::string> parseCSVLine(const std::string& line) { std::vector<std::string> fields; std::string field; bool inQuotes = false;
for (size_t i = 0; i < line.size(); ++i) { char c = line[i]; if (c == '"' && !inQuotes) { inQuotes = true; } else if (c == '"' && inQuotes) { // Verificação de aspas escapadas if (i + 1 < line.size() && line[i + 1] == '"') { field += '"'; ++i; // pula a próxima aspa } else { inQuotes = false; } } else if (c == ',' && !inQuotes) { fields.push_back(field); field.clear(); } else { field += c; } } fields.push_back(field); // último campo return fields;}
int main() { std::ifstream file("data.csv"); std::string line;
while (std::getline(file, line)) { auto fields = parseCSVLine(line); for (const auto& f : fields) { std::cout << "[" << f << "] "; } std::cout << std::endl; } return 0;}Vantagens: sem dependências externas, controle total sobre a lógica.
Desvantagens: não lida com campos multilinha (valor contendo ), requer tratamento manual de erros.
Método 2: Biblioteca libcsv
libcsv é uma biblioteca leve em C para parsing de CSV, escrita em C, mas que funciona perfeitamente em C++. Ela lida corretamente com todos os casos padrão: aspas, escape, campos multilinha, separadores personalizados.
Instalação
Baixe os fontes do SourceForge ou instale via gerenciador de pacotes:
# Linux (Debian/Ubuntu)sudo apt-get install libcsv-dev
# macOSbrew install libcsvExemplo de leitura de CSV com libcsv
#include <iostream>#include <fstream>#include <vector>#include <string>#include <cstring>#include <csv.h>
// Estrutura para armazenar dadosstruct CSVData { std::vector<std::vector<std::string>> rows; std::vector<std::string> currentRow;};
// Ca Também na biblioteca
Gerador de QR Codes em Swift: Core Image, CIFilter e Soluções Próprias
Filas de Tarefas para Rust: Visão Geral das Bibliotecas e Ferramentas Populares
Geração de relatórios PDF em PHP: visão geral das bibliotecas e exemplos de código