marți, 10 martie 2009

Conversie numar la litere

Am cautat pe Internet zilele astea, din necesitate mai mult decat din curiozitate, o metoda PHP care sa imi "traduca" un numar la formatul sau in litere (pentru completarea automata a unor documente). Din pacate, singura implementare de genul asta pe care am gasit-o functioneaza aproape oribil... Asa ca am scris eu una, pe care o postez aici, cu toate explicatiile necesare. Sper sa fie de folos cuiva (daca este, lasati si voi un comentariu cu opinia asupra codului).
<?php

/**
* Clasa face transpunerea numerelor in cuvinte
* E dezvoltata doar pentru limba ROMANA
**/
class NConv {

/**
* Methoda de separare a grupurilor de 3 cifre, si conversie (functie de nivel)
* Va returna [NaN] daca parametrul de intrare $num nu e numeric
* Va returna [huge] daca numarul este mai mare decat 999.999.999.999
* Parametrul $sep e utilizat pentru a specifica separatorul cuvintelor
* Rezultatul metodei este numarul in cuvinte (daca $sep nu e specificat, va fi un singur cuvant)
**/
function sirDeLitere($num, $sep = '') {
$num = strval($num);
if ($num == "0") return "zero";
for ($i = 0; $i < strlen($num); ++$i) if (!is_numeric($num[$i])) return "[NaN]";
if (strlen($num) > strlen("999999999999")) return "[huge]";
$conv = ""; $level = 0; $current = "";
while (strlen($num) > 0) {
if (strlen($num) > 3) {
$current = substr($num, (strlen($num) - 3));
$num = substr($num, 0, strlen($num) - 3);
} else {
$current = $num;
$num = "";
}
$crt = ($current != "000") ? $this->convGroup($current,$level, $sep) : '';
$conv = $crt.$conv;
++$level;
}
return $conv;
}

/**
* Methoda de conversie a grupurilor de 3 cifre
**/
function convGroup($nr, $level, $sep = '') {
$val = intval($nr);
if ($val == 0) return "";
$decun = $val % 100;
$hndr = floor($val / 100);
$levels = array(
'single' => array('', 'mie', 'milion', 'miliard'),
'many' => array('', 'mii', 'milioane', 'miliarde')
);
// Sufixul grupului
$sfx = $levels[($val == 1) ? 'single' : 'many'][$level];
// Diverse forme pe care numerele le pot lua, utilizate mai jos in functie de caz
$digits = array(
array("", "unu", "doi", "trei", "patru", "cinci", "sase", "sapte", "opt", "noua"),
array("", "un", "doua", "trei", "patru", "cinci", "sase", "sapte", "opt", "noua"),
array("", "o", "doua", "trei", "patru", "cinci", "sase", "sapte", "opt", "noua"),
array("", "un", "doi", "trei", "patru", "cinci", "sai", "sapte", "opt", "noua"),
array("", "un", "doua", "trei", "patru", "cinci", "sai", "sapte", "opt", "noua"),);
// Mai jos e algoritmul de conversie asa cum l-am gandit eu (admit ca nu e perfect, dar isi face treaba)
$text = $digits[2][$hndr].$sep.(($hndr == 1) ? 'suta' : (($hndr > 1) ? 'sute' : '')).$sep;
if ($decun == 0)  return $text.$sep.$sfx.$sep;
if ($decun < 10)  return $text.$digits[(($level == 0) ? 0 : (($level == 1) ? ($hndr > 0 ? 0 : 2) : 3))][$decun].$sep.$sfx.$sep;
if ($decun == 10) return $text.'zece'.$sep.$sfx.$sep;
if ($decun < 20)  return $text.$digits[3][$decun%10].'sprezece'.$sep.$sfx.$sep;
return $text.$digits[4][$decun/10].'zeci'.$sep.(($decun % 10) == '0' ? '' : ('si'.$sep.$digits[0][$decun % 10].$sep)).(($level > 0) ? ('de'.$sep) : '').$sfx.$sep;
}
}

// Run a test...
$ncv = new NConv();
echo $ncv->sirDeLitere(123456,' ');

?>

5 comentarii:

Anonim spunea...

Vreau sa-ti spun ca de doua zile caut un cod decent care sa faca asta (am devenit extrem de lenes in ultimul timp, probabil ca daca m-as fi apucat de el l-as fi terminat in cateva ore :) ). Bravo! La prima vedere pare extrem de corect in rezultate. Dar mai testam :)

Anonim spunea...

E fenomental scriptul. Functioneaza! Si ...evident ca e si de folos, mai ales in aplicatii comerciale, atunci cand ai nevoie ca anumite sume sa le scrii in litere, pe mandate postale de exemplu, sau pe unele documente bancare.

Webilă (Bogdan Rusu) spunea...

Cool stuff, bro'! Proud of ya' ;)

Anonim spunea...

Genial! Multumesc mult de tot, m-ai salvat de cateva ore de bataie de cap! Dau o bere :)

Bobo spunea...

Foarte fain. M-a scutit de ceva ore de munca. Multumesc frumos.