Da numeri a lettere in PHP
lunedì 1 dicembre 2008Ogni bravo professore di informatica delle scuole superiori dovrebbe proporre ai propri studenti questo quesito: "Scrivi una funzione che traduce un qualsiasi numero intero da 0 a 999.999.999 in lettere".
A me è successo e ricordo ancora con piacere il lunghissimo programma Pascal che avevo realizzato e che funzionava solo in parte. Dopo "qualche" anno ho trovato dieci minuti per riprendere in mano quel progettino ed è venuto meglio di quanto mi aspettassi.
Spero possa essere di ispirazione (e non solo "da copiare") anche per chi magari ha 15 anni e si ritrova ancora a dover affrontare il mio stesso problema.
function traslitterazione($numero)
{
$unita = array("","uno","due","tre","quattro","cinque","sei","sette","otto","nove");
$decina1 = array("dieci","undici","dodici","tredici","quattordici","quindici","sedici","diciassette","diciotto","diciannove");
$decine = array("","dieci","venti","trenta","quaranta","cinquanta","sessanta","settanta","ottanta","novanta");
$decineTroncate = array("","","vent","trent","quarant","cinquant","sessant","settant","ottant","novant");
$centinaia = array("","cento","duecento","trecento","quattrocento","cinquecento","seicento","settecento","ottocento","novecento");
// Inizializzo variabile contenente il risultato
$risultato = "";
// Faccio padding a 9 cifre
$stringa = str_pad($numero, 9, "0", STR_PAD_LEFT);
// Per ogni gruppo di tre cifre faccio il conto
for($i=0;$i<9;$i=$i+3)
{
// Uso una variabile temporanea
$tmp = "";
// Centinaia
$tmp .= $centinaia[$stringa[$i]];
// Decine da 2 a 9
if($stringa[$i+1] != "1")
{
if($stringa[$i+2] == "1" || $stringa[$i+2] == "8")
$tmp = $tmp . $decineTroncate[$stringa[$i+1]];
else
$tmp = $tmp . $decine[$stringa[$i+1]];
$tmp = $tmp . $unita[$stringa[$i+2]];
}
else // Undici, dodici, tredici, ecc...
{
$tmp .= $decina1[$stringa[$i+2]];
}
// Aggiungo suffissi quando necessario
if($tmp != "" && $i==0)
$tmp .= "milioni";
if($tmp != "" && $i==3)
$tmp .= "mila";
// Aggiungo a risultato finale
$risultato .= $tmp;
// Caso speciale "mille" / "un milione" -> RISOLVE BUG "unmilioneunomilauno"
if($i == 0 && $stringa[$i] == "0" && $stringa[$i+1] == "0")
$risultato = str_replace("unomilioni","unmilione",$risultato);
if($i == 3 && $stringa[$i] == "0" && $stringa[$i+1] == "0")
$risultato = str_replace("unomila","mille",$risultato);
}
// ZERO!
if($risultato == "")
return "zero";
else
return $risultato;
}
// Restituisce "tredicimilacinquecentoquarantasei"
echo traslitterazione(13546);
Potete vedere un esempio funzionante della funzione qui sopra a questo indirizzo.
Il codice non è complesso, ecco cosa fa:
- Vengono creati quattro array contenenti le stringhe
- Ricevuto in input il numero fa il padding a 9 cifre riempiendo con 0 i posti mancanti
- Per ogni gruppo di tre cifre viene calcolata la stringa corrispondente, tenendo conto di casi speciali quali undici, dodici, tredici... E troncamenti come ventuno, trentotto, ecc...
- Viene aggiunto il suffisso decimale (milioni, migliaia)
- Vengono trasformati casi speciali come zero, unmilione, mille
Che ne dite? Avete soluzioni migliori sottomano?
UPDATE!
Risolto bug segnalato nei commenti (errata traslitterazione del numero "unmilioneunomilauno" e similari). Grazie per il feedback!
In alternativa puoi abbonarti alla newsletter, riceverai un'email ogni volta che verrà pubblicato un nuovo post. Il tuo indirizzo email sarà gestito da Feedburner.












1 dicembre 2008 alle 09:16
Più che altro, il succitato professore dovrebbe saperlo fare
Comunque ne ricordo uno altrettanto divertente, che ci fecero fare al primo anno di università: convertire un numero in numeri romani (e viceversa). La soluzione, però, è fuori dalla mia memoria.
1 dicembre 2008 alle 10:27
L’ avevo fatto anche io qualche tempo fa
Anche quello dei numeri romani, solo da intero a romano però, non viceversa.
Dovrò andare a ripescarli chissà dove..
Napolux: Natale all’ insegna della programmazione ? :p
1 dicembre 2008 alle 10:41
Hm ottimo. Mi hai dato lo spunto per scervellarmi con java. Sai, sono al primo anno di informatica e una cosa del genere in java DEVO saperla fare
Fin quando non avrò finito non sbircierò nemmeno il tuo codice.
1 dicembre 2008 alle 11:41
[...] di codice è stato “archiviato”, posso dedicarmi a scrivere un altro programma di ben altro calibro. Staremo a [...]
13 gennaio 2009 alle 08:49
[...] la tombola di famiglia? Salta fuori un post sulla tombola. Mi ricordo dei tempi delle superiori? Ecco un tutorial su una “verifica” di quei tempi. Senza dimenticare tutto il [...]
6 febbraio 2009 alle 14:39
Bella lì! Mi hai evitato almeno un’ora di sbattimento! Tnx
6 febbraio 2009 alle 16:49
Ciao,
non per essere pignolo, ma la correzione dei casi speciali
# // Caso speciale: mille, un milione
# $risultato = preg_replace(“/^unomila/”,”mille”,$risultato);
non tiene conto del caso “mille” se ci sono cifre nell’ordine dei milioni.
es. 1001001 => unmilioneunomilauno
P.S: giuro che non li ho provati tutti da zero, né che ho analizzato il codice e trovato il bug, mi ha solo detto sfiga al secondo tentativo
6 febbraio 2009 alle 16:56
@ Diegobeds:
E’ un bug che mi ha segnalato un altro lettore 2 settimane fa. Nel week-end mi ci metto… Se nel frattempo trovi una soluzione… Postala!
Ci metto i credits, eh…
7 febbraio 2009 alle 12:16
@ Diegobeds:
Bug risolto e post aggiornato!