Formati e fonti di dati 4 min di lettura

Parsing di CSV: separatori, virgolette, codifiche ed esempi in vari linguaggi

Tutto sulla lettura dei CSV: separatori, virgolette, codifiche, file problematici di Excel ed esempi di codice in Python, PHP, JavaScript e Go.

TW
Team Web-Scraping.it
Raccolta dati per le esigenze del business
Pubblicato il 26 febbraio 2025

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.

csv
sku,name,price
101,"Macinacaffè, manuale",3490
102,"Teiera ""Retro""",2190

Qui "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.

python
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).

python
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.

javascript
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
<?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.

go
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.