CSV (Comma-Separated Values) è il formato tabellare più semplice: le righe del file corrispondono alle righe della tabella e i valori all’interno di ogni riga sono separati da una virgola o da un altro carattere. In CSV arrivano le esportazioni dei CRM e degli ERP, i file scaricati da Excel, i report delle piattaforme pubblicitarie e di analytics. Il formato sembra banale, ed è proprio per questo che è quello su cui si sbaglia più spesso. Questo articolo fa parte della nostra panoramica sul parsing di documenti ed è dedicato a come leggere i CSV nel modo giusto.
Perché lo «split sulla virgola» è un errore
La tentazione di smontare il CSV a mano — line.split(",") — viene a tutti e finisce quasi sempre in bug. Il punto è che il CSV prevede l’escaping: un valore con una virgola all’interno viene racchiuso tra virgolette, e le virgolette dentro un valore si raddoppiano.
sku,name,price
101,"Macinacaffè, manuale",3490
102,"Teiera ""Retro""",2190Qui "Macinacaffè, manuale" è un valore unico, non due, e Teiera "Retro" contiene virgolette. Qualsiasi split manuale li spezzerebbe. Per questo si usa sempre un lettore CSV già pronto: conosce virgolette, escaping e ritorni a capo dentro le celle.
Separatori, codifiche e BOM
Nonostante il «comma» nel nome, il separatore si rivela spesso il punto e virgola (;): è così che Excel salva i file nelle impostazioni regionali in cui la virgola è il separatore decimale — quella italiana compresa. Si incontrano anche la tabulazione (TSV) e la barra verticale. Un buon parser sa rilevare il separatore automaticamente o lo accetta come parametro.
Il secondo problema costante è la codifica. I file dei vecchi gestionali arrivano spesso in windows-1252 (latin-1) e non in UTF-8. In più, i file di Excel iniziano di frequente con un BOM (un contrassegno invisibile all’inizio) per colpa del quale il nome della prima colonna si legge come \ufeffsku invece di sku. Si cura indicando la codifica giusta in lettura (in Python, encoding="utf-8-sig", che elimina il BOM da sola).
Python
La libreria standard include il modulo csv, sufficiente nella maggior parte dei casi. La cosa più comoda è DictReader, che restituisce ogni riga come dizionario basato sulle intestazioni.
import csv
with open("prices.csv", encoding="utf-8-sig", newline="") as f:
reader = csv.DictReader(f, delimiter=";")
for row in reader:
print(row["sku"], row["name"], row["price"])Quando il CSV è grande o va analizzato al volo — filtrare, raggruppare, calcolare — si passa a pandas. Una sola riga legge il file in una tabella (DataFrame).
import pandas as pd
df = pd.read_csv("prices.csv", sep=";", encoding="utf-8-sig")
expensive = df[df["price"] > 3000]
print(expensive[["sku", "name"]])Pandas è comodo anche per convertire: lo stesso DataFrame si salva con un solo comando di nuovo in CSV, Excel o JSON.
JavaScript / Node.js
Nel browser e in Node il parser più popolare è Papa Parse: rileva il separatore automaticamente, capisce le intestazioni e sa lavorare con gli stream.
const Papa = require("papaparse");
const fs = require("fs");
const file = fs.readFileSync("prices.csv", "utf-8");
const result = Papa.parse(file, { header: true, skipEmptyLines: true });
for (const row of result.data) {
console.log(row.sku, row.name, row.price);
}Per le pipeline server con file di grandi dimensioni si sceglie più spesso csv-parse — il parser in streaming dell’ecosistema Node CSV.
PHP
La funzione integrata fgetcsv incorpora già la gestione delle virgolette, quindi basta per i compiti semplici.
<?php
$f = fopen("prices.csv", "r");
$headers = fgetcsv($f, 0, ";");
while (($row = fgetcsv($f, 0, ";")) !== false) {
$record = array_combine($headers, $row);
echo $record["sku"] . " — " . $record["name"] . "\n";
}
fclose($f);Per un lavoro più comodo — con filtri, selezione delle colonne e conversione delle codifiche — si usa la libreria league/csv.
Go
La libreria standard di Go offre il pacchetto encoding/csv, che copre la maggior parte dei casi, separatore non standard incluso.
package main
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
f, _ := os.Open("prices.csv")
defer f.Close()
r := csv.NewReader(f)
r.Comma = ';'
rows, _ := r.ReadAll()
for _, row := range rows[1:] { // saltiamo la riga di intestazione
fmt.Println(row[0], row[1], row[2])
}
}Quando il CSV non basta più
Il CSV va bene finché i dati sono piatti. Appena compaiono annidamento, più tabelle nello stesso file, formattazione, formule o celle unite, non è più un compito da CSV ma da parsing di Excel. E viceversa: se l’originale in Excel è troppo complesso per la lettura diretta, spesso lo si esporta prima in CSV e lo si elabora in modo uniforme. E se il CSV è, in sostanza, un’esportazione di eventi o di righe di un registro, dai un’occhiata agli approcci degli articoli sul parsing di TXT e sul parsing di log.
Se le tue esportazioni arrivano con codifiche «ballerine», separatori diversi da una consegna all’altra o virgolette rotte, le porteremo a un formato unico e configureremo un parsing stabile con il caricamento del risultato nel sistema che ti serve.