CSV é um daqueles formatos que ninguém ama, mas todos usam. Existe desde os anos 1970, ainda é o formato de exportação padrão de todos os aplicativos de planilha do planeta, e quase certamente está em algum lugar no seu pipeline de dados agora mesmo. O formato parece trivialmente simples — apenas valores separados por vírgulas — mas analisá-lo corretamente é surpreendentemente fácil de errar. Vamos ver como realmente funciona, onde fica complicado, e como lidar com ele em Python e JavaScript sem se prejudicar.
O Que CSV Realmente É
CSV significa Valores Separados por Vírgula (Comma-Separated Values). Um arquivo CSV é texto simples — sem codificação binária, sem metadados, sem estrutura além de linhas e colunas. Cada linha é um registro, cada valor dentro de uma linha é separado por um delimitador (geralmente uma vírgula), e a primeira linha é convencionalmente uma linha de cabeçalho com nomes de colunas. Veja como um CSV real se parece:
order_id,customer,product,quantity,unit_price,shipped
1001,Alice Nguyen,USB-C Hub,2,34.99,true
1002,Bob Martinez,Mechanical Keyboard,1,129.00,false
1003,Alice Nguyen,HDMI Cable,3,12.50,true
1004,Carol Smith,Webcam 1080p,1,79.95,falseÉ isso — seis colunas, quatro linhas de dados e um cabeçalho. Sem colchetes angulares, sem chaves, sem aspas
necessárias (ainda). Essa simplicidade é exatamente por que o CSV persiste: quase qualquer ferramenta na Terra
pode abrir, ler e produzi-lo. Excel, Google Sheets, o comando COPY do PostgreSQL, pandas, o
read.csv() do R — todos CSV nativamente. A contrapartida é que o formato tem quase nenhuma estrutura:
sem tipos, sem aninhamento, sem esquema. Todo valor é uma string até você decidir o contrário.
RFC 4180 — O Padrão Que Não É Realmente Aplicado
Existe uma especificação: RFC 4180, publicada em 2005. Define coisas como terminações de linha CRLF, escape de aspas duplas e como lidar com vírgulas incorporadas. Mas aqui está a questão — a RFC 4180 é informativa, não um padrão. Está descrevendo o que já era prática comum, não legislando. Ninguém é obrigado a segui-la, e na prática, quase ninguém a segue exatamente.
O resultado é o caos dos dialetos CSV. Você tem arquivos que usam LF em vez de CRLF, arquivos onde a primeira linha pode ou não ser um cabeçalho, arquivos com uma nova linha final e arquivos sem, arquivos com um BOM UTF-8 anexado pelo Excel. O artigo da Wikipedia sobre CSV tem um bom resumo de tudo que varia na prática. A abordagem mais segura: nunca assuma nada sobre um arquivo CSV que você não produziu, e sempre use um analisador adequado em vez de dividir ingenuamente por vírgulas.
Regras de Citação: Quando Vírgulas Aparecem Dentro dos Valores
É aqui que "apenas divida por vírgulas" desmorona. O que acontece quando um valor contém uma vírgula? Ou uma nova linha? Ou aspas duplas? A RFC 4180 — e a maioria dos analisadores do mundo real — lida com isso envolvendo o campo em aspas duplas. Aqui está o conjunto completo de regras:
- Se um campo contiver uma vírgula, uma nova linha ou aspas duplas, envolva o campo inteiro em aspas duplas
- Se um campo contiver aspas duplas, escape-as dobrando-as (
"") - Campos entre aspas podem abranger várias linhas — a nova linha se torna parte do valor
- Espaços em branco dentro de aspas são significativos e devem ser preservados
order_id,customer,notes,unit_price
1005,David Lee,"Wants gift wrapping, express shipping",45.00
1006,Emma Brown,"Said: ""please handle with care""",89.99
1007,Frank Wu,"Address:
123 Main St
Apt 4B",15.50Neste exemplo: o notes de David contém uma vírgula, então é citado. A nota de Emma
contém aspas duplas, então são dobradas dentro das aspas externas. O endereço de Frank abrange várias linhas —
as quebras de linha fazem parte do valor. Um line.split(',') ingênuo em qualquer linguagem vai
corromper completamente todos os três. É por isso que você precisa de um analisador real.
split pode fazer corretamente.Variantes de Delimitador: Tabs, Ponto e Vírgulas, Pipes
Apesar do nome, o CSV não precisa usar vírgulas. Várias variantes comuns usam delimitadores diferentes, e você encontrará todos eles no mundo real:
- TSV (Valores Separados por Tab) — usa
\tcomo delimitador. Comum em bioinformática (saída BLAST, arquivos VCF), exportações de banco de dados e em qualquer lugar onde os valores frequentemente contêm vírgulas - Separado por ponto e vírgula — o padrão no Excel para locais onde a vírgula é o separador decimal (Alemanha, França, maioria da UE). Se você já abriu um CSV de um colega europeu e obteve uma coluna gigante, é por isso
- Separado por pipe — usa
|. Comum em exportações de dados de bancos e seguradoras legadas onde tabs podem ser removidos por sistemas de mainframe - Largura fixa — tecnicamente não é CSV, mas frequentemente agrupado na mesma categoria. Colunas são preenchidas com larguras fixas em vez de delimitadas
A maioria dos analisadores CSV permite especificar o delimitador explicitamente. Ao escrever um CSV que outros consumirão, documente seu delimitador. Ao ler um que você não produziu, verifique as primeiras linhas antes de assumir. O Formatador CSV pode ajudá-lo a inspecionar e reformatar arquivos com delimitadores não padrão.
Analisando CSV em Python
A biblioteca padrão do Python inclui o
módulo csv,
e é genuinamente bom. As duas classes que você usará mais são csv.reader para acesso de linha como
lista e csv.DictReader para acesso de linha como dicionário (que é quase sempre o que você quer).
import csv
# csv.reader — each row is a list of strings
with open('orders.csv', 'r', encoding='utf-8', newline='') as f:
reader = csv.reader(f)
header = next(reader) # consume the header row
for row in reader:
order_id, customer, product, quantity, price, shipped = row
print(f"Order {order_id}: {quantity}x {product} for {customer}")
# csv.DictReader — each row is an OrderedDict keyed by the header
with open('orders.csv', 'r', encoding='utf-8', newline='') as f:
reader = csv.DictReader(f)
for row in reader:
if row['shipped'] == 'false':
print(f"Pending: {row['order_id']} — {row['customer']}")Duas coisas a sempre incluir: encoding='utf-8' (ou o que o arquivo realmente usa),
e newline=''. Esse segundo é crítico — o módulo csv faz seu próprio tratamento de
nova linha e precisa dos bytes brutos. Sem newline='', você pode obter linhas em branco extras no Windows.
Escrever é igualmente simples com csv.writer:
import csv
orders = [
{'order_id': 1008, 'customer': 'Grace Kim', 'product': 'Laptop Stand', 'quantity': 1, 'unit_price': 49.99, 'shipped': False},
{'order_id': 1009, 'customer': 'Henry Park', 'product': 'USB-C Hub', 'quantity': 2, 'unit_price': 34.99, 'shipped': True},
]
with open('new_orders.csv', 'w', encoding='utf-8', newline='') as f:
fieldnames = ['order_id', 'customer', 'product', 'quantity', 'unit_price', 'shipped']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(orders)
# To use a different delimiter (e.g. tab-separated)
with open('new_orders.tsv', 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f, delimiter='\t')
writer.writerow(['order_id', 'customer', 'product'])
writer.writerow([1008, 'Grace Kim', 'Laptop Stand'])O módulo csv cuida de toda a citação automaticamente — se um campo contém uma vírgula
ou uma nova linha, ele o envolve em aspas duplas sem você precisar pensar nisso. Esse é o ponto
de usar uma biblioteca.
Analisando CSV em JavaScript / Node.js
JavaScript não tem um analisador CSV embutido. A tentação é fazer isso:
// ❌ Don't do this — breaks immediately on quoted fields
const rows = csvText.split('\n').map(line => line.split(','));Isso falha no momento em que qualquer valor contém uma vírgula, uma nova linha dentro de aspas ou aspas duplas escapadas. Para qualquer coisa real, use uma biblioteca. PapaParse é a opção preferida — é rápida, lida com todos os casos extremos, funciona tanto no navegador quanto no Node.js e suporta streaming para arquivos grandes.
import Papa from 'papaparse';
import fs from 'fs';
// Parse a CSV string
const csvText = fs.readFileSync('orders.csv', 'utf8');
const result = Papa.parse(csvText, {
header: true, // first row becomes object keys
skipEmptyLines: true, // ignore blank lines at end of file
dynamicTyping: true, // converts "true"/"false" to booleans, numbers to numbers
});
console.log(result.data);
// [
// { order_id: 1001, customer: 'Alice Nguyen', product: 'USB-C Hub', quantity: 2, unit_price: 34.99, shipped: true },
// { order_id: 1002, customer: 'Bob Martinez', product: 'Mechanical Keyboard', quantity: 1, unit_price: 129, shipped: false },
// ...
// ]
// Check for parse errors
if (result.errors.length > 0) {
console.error('Parse errors:', result.errors);
}
// Generate CSV from an array of objects
const orders = [
{ order_id: 1008, customer: 'Grace Kim', product: 'Laptop Stand', quantity: 1, unit_price: 49.99 },
{ order_id: 1009, customer: 'Henry Park', product: 'USB-C Hub', quantity: 2, unit_price: 34.99 },
];
const csvOutput = Papa.unparse(orders);
fs.writeFileSync('export.csv', csvOutput, 'utf8');A opção dynamicTyping é útil, mas vale saber — ela converte coisas como
"34.99" para um número automaticamente. Geralmente é o que você quer, mas pode surpreender se
um campo como order_id é um número no CSV mas você o queria como string.
Desative se precisar de saída de string estrita.
Para conversões rápidas entre CSV e outros formatos, a ferramenta CSV para JSON lida com a maioria dos casos comuns no navegador sem nenhum código — útil para transformações de dados únicas. Há também CSV para XML se você precisar alimentar os dados para um sistema baseado em XML.
Armadilhas Comuns que Você Definitivamente Encontrará
Mesmo com um bom analisador, o CSV tem algumas minas terrestres bem conhecidas. Aqui estão as que aparecem com mais frequência:
- Bytes BOM do Excel. Quando o Excel exporta um CSV como "UTF-8", frequentemente adiciona
um BOM UTF-8 (
EF BB BFem hex, ou\ufeffcomo caractere). Isso faz o primeiro cabeçalho de coluna parecerorder_idem vez deorder_id. Em Python, abra o arquivo comencoding='utf-8-sig'em vez deutf-8para removê-lo automaticamente. O PapaParse lida com isso de forma transparente. - Terminações de linha CRLF vs LF. A RFC 4180 especifica CRLF (
\r\n), mas ferramentas Unix produzem LF (\n) e arquivos Mac antigos usam CR (\r) sozinho. É por isso que o módulocsvdo Python precisa denewline=''— ele lida com todos os três internamente. Se você estiver lendo bytes brutos e dividindo manualmente, precisará remover\rexplicitamente. - Problemas de codificação. CSV não tem como declarar sua própria codificação — diferente
do
<meta charset>do HTML ou do<?xml encoding="..."?>do XML. O Excel frequentemente salva arquivos em Windows-1252 (a.k.a. CP1252) em vez de UTF-8, o que distorce caracteres acentuados. Se você ver caracteres comoéem vez deé, você tem um arquivo UTF-8 sendo decodificado como Latin-1, ou vice-versa. Sempre estabeleça a codificação fora de banda com quem produz o arquivo. - Números que parecem datas. O Excel converte silenciosamente valores como
1-2ou03/04para datas ao abrir ou salvar. Se você estiver exportando códigos de produto ou números de versão, prefixe-os com uma aspa simples no Excel ('1-2) para evitar isso — ou diga a quem produz o arquivo para fazer o mesmo. - Vírgulas finais. Alguns exportadores emitem uma vírgula no final de cada linha, o que cria uma coluna vazia fantasma. Um analisador robusto ignora isso; uma divisão ingênua cria um elemento de string vazia extra.
Se estiver lidando com um arquivo que parece estranho, o Validador CSV pode rapidamente dizer se o arquivo está bem formado e sinalizar problemas de codificação ou estruturais antes que você tente processá-lo.
CSV vs JSON vs Excel — Quando Usar o Quê
Esses três formatos se sobrepõem muito na prática, mas cada um tem um ponto forte claro:
- Use CSV quando estiver movendo dados planos e tabulares entre sistemas — exportações de banco de dados, pipelines analíticos, importações de planilhas, carregamento em massa de dados. É universalmente suportado, pequeno em tamanho e facilmente diferenciável no git. A restrição: é plano. Sem aninhamento, sem tipos, sem relacionamentos.
- Use JSON quando os dados são hierárquicos ou o esquema importa. Um pedido com vários itens de linha, um arquivo de configuração com objetos aninhados, uma resposta de API — esses são naturalmente JSON. O CSV forçaria você a desnormalizar os dados ou inventar sua própria convenção de aninhamento. A especificação JSON é limpa e inequívoca; o formato preserva tipos (números, booleanos, null, arrays, objetos).
- Use Excel (.xlsx) quando a saída é para humanos, não máquinas. Formatação, fórmulas, várias planilhas, gráficos — se um usuário de negócios é o consumidor final, o Excel é frequentemente a escolha certa. Mas nunca o use como formato de intercâmbio entre sistemas. A especificação OOXML é enorme e o formato é frágil entre versões.
Há uma heurística prática: se você naturalmente visualizaria os dados em uma planilha, o CSV é provavelmente adequado. Se visualizaria em uma árvore ou em um editor de código, use JSON. Se estiver enviando para um stakeholder de negócios que vai filtrar e ordenar, use Excel.
Conclusão
O CSV é simples por design e enganosamente complicado na prática. O formato não tem padrão aplicado,
vem em várias variantes de delimitador e depende de regras de citação que quebram toda tentativa de análise manual.
A correção é sempre a mesma: use um analisador real (o módulo csv embutido do Python, ou PapaParse
em JavaScript), sempre especifique a codificação explicitamente e fique atento aos bytes BOM do Excel. Uma vez que
você tenha um analisador confiável, o CSV é na verdade um ótimo formato — rápido de produzir, fácil de inspecionar
em qualquer editor de texto e suportado em todos os lugares. Para trabalho diário com arquivos CSV, as ferramentas
CSV para JSON, Formatador CSV, e
Validador CSV lidam com as operações comuns sem escrever uma linha de código.