Integrar sistemas com arquivos bancários CNAB 240 e CNAB 400 (FEBRABAN) costuma ser um desafio para desenvolvedores. Por se tratar de um formato posicional de colunas fixas sem delimitadores como vírgula ou ponto e vírgula, qualquer erro no fatiamento da string pode corromper dados financeiros importantes, como valores pagos, datas de liquidação ou códigos de ocorrência.
Neste artigo prático, vamos mostrar como estruturar um parser robusto em Node.js (TypeScript) e Python para ler arquivos de Remessa (.rem) e Retorno (.ret), extrair registros com segurança e validar a integridade do arquivo.
O Conceito de Slicing Posicional
No padrão CNAB, cada linha representa um registro e cada campo ocupa posições específicas (1-indexed na documentação da FEBRABAN). Em linguagens de programação (0-indexed), devemos converter essas posições para índices de substring:
| Campo FEBRABAN | Posição Manual (FEBRABAN) | Índices em Código (0-indexed) | Tamanho |
|---|---|---|---|
| Código do Banco | 001 a 003 | slice(0, 3) |
3 caracteres |
| Lote de Serviço | 004 a 007 | slice(3, 7) |
4 caracteres |
| Tipo de Registro | 008 a 008 | slice(7, 8) |
1 caractere |
Exemplo 1: Parser CNAB em Node.js / TypeScript
Abaixo está um exemplo limpo utilizando TypeScript para parsear o Header e os Detalhes de um arquivo CNAB 240 de Retorno Bancário:
import * as fs from 'fs';
import * as path from 'path';
interface CNAB240Header {
codigoBanco: string;
lote: string;
tipoInscricao: string;
numeroInscricao: string;
nomeEmpresa: string;
}
interface CNAB240SegmentoP {
nossoNumero: string;
vencimento: string;
valorTitulo: number;
}
export function parseCNAB240(conteudoArquivo: string) {
const linhas = conteudoArquivo.split(/
?
/).filter(l => l.length > 0);
const titulos: CNAB240SegmentoP[] = [];
for (const linha of linhas) {
// Validação de comprimento da linha
if (linha.length !== 240) {
console.warn(`Linha ignorada: tamanho ${linha.length} é diferente de 240.`);
continue;
}
const tipoRegistro = linha.slice(7, 8); // Posição 8
// Registro Tipo 0: Header de Arquivo
if (tipoRegistro === '0') {
const banco = linha.slice(0, 3);
const empresa = linha.slice(72, 102).trim();
console.log(`Processando arquivo do banco ${banco} para ${empresa}`);
}
// Registro Tipo 3: Segmento de Detalhe
if (tipoRegistro === '3') {
const codigoSegmento = linha.slice(13, 14); // Posição 14
// Segmento P (Dados do Título)
if (codigoSegmento === 'P') {
const nossoNumero = linha.slice(37, 57).trim();
const dataVenc = linha.slice(77, 85); // DDMMAAAA
const valorEmCents = parseInt(linha.slice(85, 100), 10);
titulos.push({
nossoNumero,
vencimento: `${dataVenc.slice(0,2)}/${dataVenc.slice(2,4)}/${dataVenc.slice(4,8)}`,
valorTitulo: valorEmCents / 100
});
}
}
}
return titulos;
}
Exemplo 2: Parser CNAB em Python
Em Python, podemos utilizar a sintaxe nativa de fatiamento de strings (string[start:end]) para ler um arquivo CNAB 400 de cobrança:
def parse_cnab_400(filepath: str):
registros_pagos = []
with open(filepath, 'r', encoding='latin1') as f:
for index, line in enumerate(f, start=1):
line = line.rstrip('
')
if len(line) != 400:
print(f"Alerta Linha {index}: Comprimento incorreto ({len(line)} caracteres)")
continue
tipo_registro = line[0:1]
# Registro Detalhe Tipo 1 (Cobrança)
if tipo_registro == '1':
nosso_numero = line[62:70].strip()
carteira = line[107:108]
ocorrencia = line[108:110] # 06 = Liquidação/Pago
data_ocorrencia = line[110:116] # DDMMAA
valor_pago_cents = int(line[253:266] or '0')
# Ocorrência 06 indica título pago
if ocorrencia == '06':
registros_pagos.append({
"nosso_numero": nosso_numero,
"carteira": carteira,
"data_pagamento": f"{data_ocorrencia[0:2]}/{data_ocorrencia[2:4]}/20{data_ocorrencia[4:6]}",
"valor_pago": valor_pago_cents / 100.0
})
return registros_pagos
# Exemplo de execução
# pagamentos = parse_cnab_400('retorno_itau.ret')
# print(pagamentos)
Boas Práticas de Engenharia ao Tratar CNAB
- Encoding de Caracteres: Muitos bancos legados enviam arquivos CNAB em encoding
ISO-8859-1 (Latin1)ouASCIIem vez deUTF-8. Sempre trate a codificação do arquivo ao ler o buffer. - Tratamento de Valores Monetários: Nunca converta diretamente os dígitos inteiros sem dividir por 100.0 (ex:
000000015050representaR$ 150,50). - Idempotência na Processamento de Retorno: Arquivos de retorno bancários podem ser baixados mais de uma vez. Sempre utilize a combinação de
Banco + Nosso Número + Data de Ocorrênciacomo chave de idempotência no banco de dados.
Testando e Inspecionando Arquivos CNAB
Quer verificar se o seu arquivo CNAB está configurado corretamente com as posições certas antes de colocar o código em produção? Utilize a ferramenta Leitor e Decodificador de CNAB do DevThru para visualizar os campos fatiados com syntax highlighting instantâneo!
🛠️ Experimente na prática
Use nossas ferramentas online gratuitas — sem cadastro, direto no navegador.
