CSV no Excel em português: ponto e vírgula, acentos e zeros à esquerda

O Excel configurado em português usa ponto e vírgula como separador, porque a vírgula é o separador decimal, e só reconhece UTF-8 se o arquivo começar com o BOM. Este guia explica os problemas mais comuns com CSV no Brasil e mostra como gerar um CSV que o Excel abre certo e como ler o que ele salva, em JavaScript, Python e PHP.

Por Leonardo Gaertner · Publicado em

Os três problemas de sempre

  • Tudo numa coluna só: o arquivo usa vírgula, e o Excel em português espera ponto e vírgula. O separador segue a configuração regional do sistema, não o arquivo.
  • Acentos quebrados (João no lugar de João): o arquivo está em UTF-8 sem BOM, e o Excel o lê como Windows-1252.
  • Números errados: 1.5 vira data ou texto, e CEPs como 01310100 perdem o zero à esquerda.

O conversor de JSON para CSV permite escolher o separador e gera o arquivo com BOM. O conversor de CSV para JSON detecta o separador sozinho.

Gerar CSV para o Excel em JavaScript

Três ajustes resolvem: ponto e vírgula como separador, vírgula nos números decimais e o BOM (\uFEFF) no começo. Campos com ponto e vírgula, aspas ou quebra de linha vão entre aspas, com as aspas internas duplicadas.

JavaScript
// Monta um CSV que o Excel em português abre certo: ponto e vírgula, vírgula
// decimal e BOM para reconhecer o UTF-8
function csvParaExcel(linhas) {
  const colunas = Object.keys(linhas[0]);
  const celula = (v) => {
    const s = v == null ? '' : typeof v === 'number' ? String(v).replace('.', ',') : String(v);
    return /[;"\r\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
  };
  const texto = [colunas, ...linhas.map((l) => colunas.map((c) => l[c]))]
    .map((campos) => campos.map(celula).join(';'))
    .join('\r\n');
  return '' + texto;
}

Para baixar no navegador, crie um Blob com type "text/csv;charset=utf-8" a partir do texto.

Ler e escrever em Python

O módulo csv cuida das aspas. A codificação utf-8-sig escreve o BOM na gravação e o ignora na leitura, e newline="" evita linhas em branco extras no Windows.

Python
import csv


def ler_csv_excel(caminho: str) -> list[dict]:
    # utf-8-sig ignora o BOM que o Excel grava no começo do arquivo
    with open(caminho, encoding="utf-8-sig", newline="") as f:
        return list(csv.DictReader(f, delimiter=";"))


def escrever_csv_excel(caminho: str, linhas: list[dict]) -> None:
    with open(caminho, "w", encoding="utf-8-sig", newline="") as f:
        w = csv.DictWriter(f, fieldnames=list(linhas[0]), delimiter=";")
        w.writeheader()
        w.writerows(linhas)

Ler em PHP

O fgetcsv não pula o BOM sozinho, então o exemplo confere os três primeiros bytes. O último argumento vazio desliga o caractere de escape próprio do PHP, que não faz parte do padrão CSV (e passá-lo explicitamente evita o aviso de depreciação no PHP 8.4).

PHP
<?php
function lerCsvExcel(string $caminho): array
{
    $f = fopen($caminho, 'r');
    if (fread($f, 3) !== "\xEF\xBB\xBF") {
        rewind($f); // não tinha BOM: volta ao começo
    }
    $cabecalho = fgetcsv($f, null, ';', '"', '');
    $linhas = [];
    while (($campos = fgetcsv($f, null, ';', '"', '')) !== false) {
        if ($campos !== [null]) { // pula linhas em branco
            $linhas[] = array_combine($cabecalho, $campos);
        }
    }
    fclose($f);
    return $linhas;
}

Cuidados

  • Arquivos salvos no Excel como "CSV (separado por vírgulas)" costumam vir em Windows-1252, não em UTF-8. Se os acentos chegarem quebrados, leia com encoding="cp1252" no Python ou converta com mb_convert_encoding no PHP. A opção "CSV UTF-8" do Excel evita o problema.
  • Valores que começam com =, +, - ou @ podem ser executados como fórmula quando o arquivo é aberto (a chamada injeção de CSV). Em dados vindos de usuários, prefixe esses valores com um apóstrofo.
  • Para manter zeros à esquerda (CEP, CPF), importe a coluna como texto no Excel. No arquivo, o valor já está certo: é a abertura que o transforma em número.
  • Se o arquivo não for para o Excel, e sim para outro sistema, use o padrão: vírgula, UTF-8 sem BOM e ponto decimal.

Achou um erro neste guia? Avise por e-mail.

Perguntas frequentes

Por que o CSV abre tudo em uma coluna no Excel?

O Excel usa o separador de listas da configuração regional. No Brasil, é ponto e vírgula, porque a vírgula é o separador decimal. Um CSV com vírgula abre tudo em uma coluna. Gere o arquivo com ponto e vírgula ou importe pelo menu Dados, opção De Texto/CSV, que permite escolher o separador.

Como fazer o Excel abrir CSV com acentos?

Salve o arquivo em UTF-8 com BOM, os três bytes EF BB BF no começo. Sem eles, o Excel lê o arquivo como Windows-1252 e troca os acentos por símbolos estranhos.

O que é o BOM?

É uma marca invisível no início do arquivo que indica a codificação. Em UTF-8, são os bytes EF BB BF. Muitos programas ignoram, mas o Excel depende dela para reconhecer o UTF-8.

Como evitar que o Excel tire o zero à esquerda do CEP?

Na importação, defina a coluna como texto. Abrir o arquivo com duplo clique faz o Excel converter a coluna em número e perder os zeros, mesmo que o arquivo esteja certo.