JavaScript Python PHP
import * as __biblioteca0 from "csv-parse/browser/esm/sync";
import * as __biblioteca1 from "csv-stringify/browser/esm/sync";
function executar(input = 'nome,codigo\nJoão,00123', delimiter = ',') {
const parse = __biblioteca0["parse"];
const stringify = __biblioteca1["stringify"];
function csvDelimiter(value) {
if (value === ',' || value === ';' || value === '\t')
return value;
if (value === 'Tabulação')
return '\t';
throw new Error('Escolha vírgula, ponto e vírgula ou tabulação.');
}
function csvToJson(input, delimiter = ',') {
const separator = csvDelimiter(delimiter);
if (input.length > 1000000)
throw new Error('A entrada excede o limite de 1 milhão de caracteres.');
let rows;
try {
rows = parse(input, { delimiter: separator, bom: true, cast: false, columns: false, skip_empty_lines: true, info: true, record_delimiter: ['\r\n', '\n'], relax_column_count: false }); // info:true changes the runtime shape; the library's overload omits it.
}
catch (cause) {
const error = cause;
const position = error.lines ? ` (linha ${error.lines}${typeof error.column === 'number' ? `, campo ${Number(error.column) + 1}` : ''})` : '';
const explanation = error.code === 'CSV_RECORD_INCONSISTENT_FIELDS_LENGTH'
? 'A linha tem uma quantidade de campos diferente do cabeçalho.'
: error.code === 'CSV_QUOTE_NOT_CLOSED' ? 'Campo entre aspas sem fechamento.'
: error.code === 'INVALID_OPENING_QUOTE' || error.code === 'CSV_INVALID_CLOSING_QUOTE' ? 'Aspas inválidas: envolva o campo em aspas e escape aspas internas com duas aspas.' : 'Erro de estrutura CSV.';
throw new Error(`CSV inválido${position}: ${explanation} (${error.code ?? 'erro'}) ${error.message}`);
}
if (!rows.length)
throw new Error('Informe um CSV com uma linha de cabeçalho.');
const headers = rows[0].record;
const seen = new Set();
headers.forEach((header, index) => {
if (!header.trim())
throw new Error(`Cabeçalho vazio (linha ${rows[0].info.lines}, campo ${index + 1}).`);
if (seen.has(header))
throw new Error(`Cabeçalho duplicado "${header}" (linha ${rows[0].info.lines}, campo ${index + 1}).`);
seen.add(header);
});
const records = rows.slice(1).map(({ record }) => {
const object = Object.create(null);
headers.forEach((header, index) => { object[header] = record[index]; });
return object;
});
return JSON.stringify(records, null, 2);
}
return csvToJson(input, delimiter);
}
import csv
import io
import json
def executar(input="nome,codigo\nJoão,00123", delimiter=","):
delimiter = "\t" if delimiter == "Tabulação" else delimiter
if delimiter not in (",", ";", "\t"): raise ValueError("Delimitador inválido.")
if len(input.encode("utf-16-le", errors="surrogatepass")) // 2 > 1000000: raise ValueError("Limite de 1 milhão de caracteres.")
# Validate opening/closing quotes; csv.reader(strict=True) tolerates bare quotes.
state = "start"
for position, character in enumerate(input.lstrip("\ufeff"), 1):
if state == "quoted":
if character == '"': state = "closed"
elif state == "closed":
if character == '"': state = "quoted"
elif character == delimiter: state = "start"
elif character in "\r\n": state = "start"
else: raise ValueError(f"Aspas inválidas na posição {position}.")
elif character == '"' and state != "start":
raise ValueError(f"Aspas inválidas na posição {position}.")
elif character == '"': state = "quoted"
elif character == delimiter or character in "\r\n": state = "start"
else: state = "bare"
if state == "quoted": raise ValueError("Campo entre aspas sem fechamento.")
reader = csv.reader(io.StringIO(input.removeprefix("\ufeff"), newline=""), delimiter=delimiter, strict=True)
headers = None
records = []
try:
for row in reader:
if not row: continue
if headers is None:
if any(not key.strip() for key in row) or len(set(row)) != len(row):
raise ValueError(f"Cabeçalho vazio ou duplicado na linha {reader.line_num}.")
headers = row
else:
if len(row) != len(headers): raise ValueError(f"Quantidade incorreta de campos na linha {reader.line_num}.")
records.append(dict(zip(headers, row)))
except csv.Error as error:
raise ValueError(f"CSV inválido na linha {reader.line_num}: {error}") from error
if headers is None: raise ValueError("Informe um cabeçalho CSV.")
return json.dumps(records, ensure_ascii=False, indent=2)
<?php
function executar($input = "nome,codigo\nJoão,00123", $delimiter = ',') {
$delimiter = $delimiter === 'Tabulação' ? "\t" : $delimiter;
if (!in_array($delimiter, [',', ';', "\t"], true)) throw new InvalidArgumentException('Delimitador inválido.');
if (!mb_check_encoding($input, 'UTF-8') || mb_strlen(mb_convert_encoding($input, 'UTF-16LE', 'UTF-8'), 'UTF-16LE') > 1000000) throw new InvalidArgumentException('UTF-8 inválido ou entrada muito longa.');
if (str_starts_with($input, "\xEF\xBB\xBF")) $input = substr($input, 3);
$state = 'start'; $line = 1;
for ($i = 0; $i < strlen($input); $i++) {
$c = $input[$i];
if ($state === 'quoted') { if ($c === '"') $state = 'closed'; }
elseif ($state === 'closed') {
if ($c === '"') $state = 'quoted';
elseif ($c === $delimiter || $c === "\r" || $c === "\n") $state = 'start';
else throw new InvalidArgumentException('Aspas inválidas na linha '.$line);
} elseif ($c === '"') {
if ($state !== 'start') throw new InvalidArgumentException('Aspas inválidas na linha '.$line);
$state = 'quoted';
} elseif ($c === $delimiter || $c === "\r" || $c === "\n") $state = 'start';
else $state = 'bare';
if ($c === "\n") $line++;
}
if ($state === 'quoted') throw new InvalidArgumentException('Campo entre aspas sem fechamento.');
$stream = fopen('php://temp', 'r+'); fwrite($stream, $input); rewind($stream);
$headers = null; $records = [];
try {
while (($row = fgetcsv($stream, 0, $delimiter, '"', '')) !== false) {
if ($row === [null]) continue;
if ($headers === null) {
if (array_filter($row, fn($key) => trim($key) === '') || count(array_unique($row)) !== count($row)) throw new InvalidArgumentException('Cabeçalho vazio ou duplicado.');
$headers = $row;
} else {
if (count($row) !== count($headers)) throw new InvalidArgumentException('Quantidade incorreta de campos no registro '.(count($records) + 1));
$object = new stdClass();
foreach ($headers as $index => $key) $object->{$key} = $row[$index];
$records[] = $object;
}
}
} finally { fclose($stream); }
if ($headers === null) throw new InvalidArgumentException('Informe um cabeçalho CSV.');
return preg_replace_callback('/^( +)/m', fn($match) => str_repeat(' ', strlen($match[1]) / 2), json_encode($records, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
}