Ogni italiano ha sedici caratteri che lo identificano, e quasi nessuno sa da
dove vengono. Non sono casuali: sono il risultato di un algoritmo pubblicato
nel decreto ministeriale del 23 dicembre 1976, deterministico e completamente
ricostruibile. Se conosci nome, cognome, data e luogo di nascita di una
persona, il suo codice fiscale lo calcoli a mano su un foglio.
Ho implementato quell'algoritmo per un sito di calcolatori fiscali e poi l'ho
estratto in una libreria open source. Questo è quello che ho imparato per
strada, compresi i due punti dove quasi tutte le implementazioni sbagliano.
Le prime sei lettere: cognome e nome
Le prime tre lettere vengono dal cognome: si prendono le consonanti in ordine,
e se non bastano si aggiungono le vocali.
ROSSI → consonanti RSS → RSS
BIANCHI → consonanti BNCH, prime tre → BNC
Se il cognome è troppo corto si completa con la X:
LI → consonante L + vocale I → LI + padding → LIX
Il nome segue la stessa logica con un'eccezione: se le consonanti sono
quattro o più, non si prendono le prime tre ma la prima, la terza e la
quarta.
MARIO → consonanti MR (solo due) → MR + vocale A → MRA
FRANCESCO → consonanti FRNCSC (sei) → 1ª, 3ª, 4ª = F, N, C → FNC
È la regola che rompe la maggior parte delle implementazioni fatte in fretta,
e in Italia i nomi con quattro consonanti sono comunissimi.
La data di nascita, e il trucco del sesso
Due cifre per l'anno, poi una lettera per il mese secondo questa sequenza:
A B C D E H L M P R S T
gen feb mar apr mag giu lug ago set ott nov dic
Le lettere saltate (F, G, I, N, O, Q) servono a evitare ambiguità in lettura.
Poi due cifre per il giorno, con una particolarità: per le donne si somma
40. Chi è nata il 15 avrà 55. È il modo con cui l'algoritmo codifica il
sesso senza spendere un carattere in più: 01-31 uomini, 41-71 donne.
Il luogo: i codici Belfiore
Quattro caratteri per il comune di nascita, secondo il codice catastale (detto
Belfiore): Roma è H501, Milano F205, Napoli F839.
Chi è nato all'estero usa il codice dello stato, che inizia sempre per Z:
Francia Z110, Germania Z112, Stati Uniti Z404. La città estera non entra
nel codice: due persone nate a Parigi e a Lione hanno lo stesso Z110.
Il dettaglio che quasi tutte le librerie ignorano: servono anche i comuni
soppressi. Chi è nato in un comune che oggi non esiste più mantiene il
codice storico, e un archivio che contenga solo i comuni attuali sbaglierà il
calcolo per un pezzo della popolazione anziana.
Il carattere di controllo
L'ultimo carattere è un checksum sui quindici precedenti. Ogni carattere vale
un numero, ma il valore dipende dalla posizione: c'è una tabella per le
posizioni dispari e una per le pari.
let somma = 0;
for (let i = 0; i < 15; i++) {
somma += i % 2 === 0 ? DISPARI[cf[i]] : PARI[cf[i]];
}
const controllo = String.fromCharCode(65 + (somma % 26));
La tabella dei pari è banale (0→0, A→0, B→1...), quella dei dispari è
una sequenza apparentemente arbitraria (0→1, 1→0, 2→5, 3→7, 4→9,
5→13...) scelta per massimizzare la capacità di rilevare errori di
trascrizione, compresa l'inversione di due caratteri adiacenti.
È il motivo per cui un codice fiscale scritto male viene quasi sempre
scoperto: cambia una lettera e il checksum non torna.
L'omocodia: il caso che rompe i validatori
Qui arriva la parte che manda in crisi i validatori scritti male.
L'algoritmo non garantisce l'unicità. Due persone con dati anagrafici
simili possono generare lo stesso codice. Quando succede, l'Agenzia delle
Entrate assegna al secondo soggetto un codice modificato: le cifre vengono
sostituite da lettere, partendo da destra, secondo questa tabella:
0→L 1→M 2→N 3→P 4→Q 5→R 6→S 7→T 8→U 9→V
e il carattere di controllo viene ricalcolato sul codice modificato.
Conseguenza pratica: esistono codici fiscali perfettamente validi che hanno
lettere dove un validatore ingenuo si aspetta cifre. Se il tuo form
rifiuta un codice con una lettera in posizione 7, stai rifiutando cittadini
italiani con un codice regolarmente assegnato.
La validazione corretta è: riporta le lettere alle cifre secondo la tabella,
poi verifica il carattere di controllo sul codice originale.
const POSIZIONI_CIFRE = [6, 7, 9, 10, 12, 13, 14];
// per ognuna, se non è una cifra, sostituisci secondo la tabella
L'altro tranello: i caratteri non latini
Questo l'ho scoperto scrivendo i test. Il modo standard di togliere gli
accenti in JavaScript è:
s.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
Funziona per à, è, ò: la normalizzazione NFD le scompone in lettera base
più diacritico, e il diacritico viene rimosso.
Non funziona per i caratteri latini estesi dove il segno fa parte del
glifo e non è scomponibile: Đ (serbo, croato), Ł (polacco), Ø (danese,
norvegese), ß (tedesco), Æ. Questi sopravvivono alla normalizzazione, poi
il filtro [^A-Z] li cancella.
Risultato: per un nome come Đorđe le due Đ spariscono e il codice esce
sbagliato. Che non è un caso di scuola, considerando quante persone con nomi
serbi, polacchi o scandinavi vivono in Italia.
La soluzione è una tabella di traslitterazione esplicita, applicata prima
della normalizzazione:
const TRANSLITTERA = {
'Đ': 'D', 'Ł': 'L', 'Ø': 'O', 'ß': 'SS', 'Æ': 'AE', /* ... */
};
La libreria
L'ho pubblicata come codice-fiscale-it: TypeScript, zero dipendenze,
licenza MIT, con l'archivio completo dei comuni (compresi i soppressi) e degli
stati esteri.
npm install codice-fiscale-it
import { calcolaDaComune, verificaCodiceFiscale, decodificaCodiceFiscale }
from 'codice-fiscale-it';
calcolaDaComune({
cognome: 'Rossi', nome: 'Mario', sesso: 'M',
giorno: 1, mese: 1, anno: 1980, comune: 'Roma',
});
// => 'RSSMRA80A01H501U'
verificaCodiceFiscale('RSSMRA80A01H501U'); // => true
decodificaCodiceFiscale('RSSMRA80A01H501U', 2026);
// => { sesso: 'M', giorno: 1, mese: 1, annoStimato: 1980,
// belfiore: 'H501', omocodia: false, controlloValido: true }
Codice su GitHub.
Due cose che nessuna libreria può fare
Non può generare il codice omocodico. La variante la decide solo l'Agenzia
delle Entrate quando rileva il conflitto: il calcolo produce sempre il codice
base. Se il risultato non coincide con la tessera sanitaria, fa fede la
tessera.
Non può ricavare il secolo con certezza. L'anno ha due cifre: 58 può
essere 1958 o 2058. Si può solo stimare usando l'anno corrente come pivot, e
va detto esplicitamente all'utente invece di far finta che il dato sia certo.
L'algoritmo nasce dal motore di
quantomispetta.it, dove
ogni calcolo viene mostrato passo per passo con la norma di riferimento.
Top comments (0)