'zéro', 1=>'un', 2=>'deux', 3=>'trois', 4=>'quatre', 5=>'cinq', 6=>'six', 7=>'sept', 8=>'huit', 9=>'neuf', 10=>'dix', 11=>'onze', 12=>'douze', 13=>'treize', 14=>'quatorze', 15=>'quinze', 16=>'seize', 17=>'dix sept', 18=>'dix huit', 19=>'dix neuf', 20=>'vingt', 21=>'vingt et un', 22=>'vingt deux', 23=>'vingt trois', 24=>'vingt quatre', 25=>'vingt cinq', 26=>'vingt six', 27=>'vingt sept', 28=>'vingt huit', 29=>'vingt neuf', 30=>'trente', 40=>'quarante', 50=>'cinquante', 60=>'soixante', 70=>'soixante dix', 80=>'quatre vingt', 90=>'quatre vingt dix'); public function ChiffresEnLettres($chiffre) { return array_search($chiffre, self::$tabChiffresEnLEttres); } } /* define('NEL_SEPTANTE', 0x0001); define('NEL_HUITANTE', 0x0002); define('NEL_OCTANTE', 0x0004); define('NEL_NONANTE', 0x0008); define('NEL_BELGIQUE', NEL_SEPTANTE|NEL_NONANTE); define('NEL_VVF', NEL_SEPTANTE|NEL_HUITANTE|NEL_NONANTE); define('NEL_ARCHAIQUE', NEL_SEPTANTE|NEL_OCTANTE|NEL_NONANTE); define('NEL_SANS_MILLIARD', 0x0010); define('NEL_AVEC_ZILLIARD', 0x0020); define('NEL_TOUS_ZILLIONS', 0x0040); define('NEL_RECTIF_1990', 0x0100); define('NEL_ORDINAL', 0x0200); define('NEL_NIEME', 0x0400); # Le tableau associatif $NEL contient toutes les variables utilisées # de façon globale dans ce module. ATTENTION : ce nom est assez court, # et cela pourrait poser des problèmes de collision avec une autre # variable si plusieurs modules sont inclus dans le même programme. $NEL = array( '1-99' => array( # 0-19 '', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf', 'dix', 'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf', # 20-29 'vingt', 'vingt et un', 'vingt-deux', 'vingt-trois', 'vingt-quatre', 'vingt-cinq', 'vingt-six', 'vingt-sept', 'vingt-huit', 'vingt-neuf', # 30-39 'trente', 'trente et un', 'trente-deux', 'trente-trois', 'trente-quatre', 'trente-cinq', 'trente-six', 'trente-sept', 'trente-huit', 'trente-neuf', # 40-49 'quarante', 'quarante et un', 'quarante-deux', 'quarante-trois', 'quarante-quatre', 'quarante-cinq', 'quarante-six', 'quarante-sept', 'quarante-huit', 'quarante-neuf', # 50-59 'cinquante', 'cinquante et un', 'cinquante-deux', 'cinquante-trois', 'cinquante-quatre', 'cinquante-cinq', 'cinquante-six', 'cinquante-sept', 'cinquante-huit', 'cinquante-neuf', # 60-69 'soixante', 'soixante et un', 'soixante-deux', 'soixante-trois', 'soixante-quatre', 'soixante-cinq', 'soixante-six', 'soixante-sept', 'soixante-huit', 'soixante-neuf', # 70-79 'septante', 'septante et un', 'septante-deux', 'septante-trois', 'septante-quatre', 'septante-cinq', 'septante-six', 'septante-sept', 'septante-huit', 'septante-neuf', # 80-89 'huitante', 'huitante et un', 'huitante-deux', 'huitante-trois', 'huitante-quatre', 'huitante-cinq', 'huitante-six', 'huitante-sept', 'huitante-huit', 'huitante-neuf', # 90-99 'nonante', 'nonante et un', 'nonante-deux', 'nonante-trois', 'nonante-quatre', 'nonante-cinq', 'nonante-six', 'nonante-sept', 'nonante-huit', 'nonante-neuf' ), 'illi' => array('', 'm', 'b', 'tr', 'quatr', 'quint', 'sext'), 'maxilli' => 0, # voir plus loin 'de_maxillions' => '', # voir plus loin 'septante' => false, # valeurs possibles : (false|true) 'huitante' => false, # valeurs possibles : (false|true|'octante') 'nonante' => false, # valeurs possibles : (false|true) 'zillions' => false, # valeurs possibles : (false|true) 'zilliard' => 1, # valeurs possibles : (0|1|2) 'rectif' => false, # valeurs possibles : (false|true) 'ordinal' => false, # valeurs possibles : (false|true|'nieme') 'separateur' => ' ' ); # Si le tableau $NEL['illi'] s'arrête à 'sext', alors les deux valeurs # suivantes sont respectivement '6' et ' de sextillions'. $NEL['maxilli'] = count($NEL['illi']) - 1; $NEL['de_maxillions'] = " de {$NEL['illi'][$NEL['maxilli']]}illions"; function enlettres_options($options, $separateur=NULL) { global $NEL; if ($options !== NULL) { $NEL['septante'] = ($options & NEL_SEPTANTE) ? true : false; $NEL['huitante'] = ($options & NEL_OCTANTE) ? 'octante' : (($options & NEL_HUITANTE) ? true : false); $NEL['nonante'] = ($options & NEL_NONANTE) ? true : false; $NEL['zillions'] = ($options & NEL_TOUS_ZILLIONS) ? true : false; $NEL['zilliard'] = ($options & NEL_AVEC_ZILLIARD) ? 2 : (($options & NEL_SANS_MILLIARD) ? 0 : 1); $NEL['rectif'] = ($options & NEL_RECTIF_1990) ? true : false; $NEL['ordinal'] = ($options & NEL_NIEME) ? 'nieme' : (($options & NEL_ORDINAL) ? true : false); } if ($separateur !== NULL) { $NEL['separateur'] = $separateur; } } function enlettres_par3($par3) { global $NEL; if ($par3 == 0) return ''; $centaine = floor($par3 / 100); $par2 = $par3 % 100; $dizaine = floor($par2 / 10); # On traite à part les particularités du français de référence # 'soixante-dix', 'quatre-vingts' et 'quatre-vingt-dix'. $nom_par2 = NULL; switch ($dizaine) { case 7: if ($NEL['septante'] === false) { if ($par2 == 71) $nom_par2 = 'soixante et onze'; else $nom_par2 = 'soixante-' . $NEL['1-99'][$par2 - 60]; } break; case 8: if ($NEL['huitante'] === false) { if ($par2 == 80) $nom_par2 = 'quatre-vingts'; else $nom_par2 = 'quatre-vingt-' . $NEL['1-99'][$par2 - 80]; } break; case 9: if ($NEL['nonante'] === false) { $nom_par2 = 'quatre-vingt-' . $NEL['1-99'][$par2 - 80]; } break; } if ($nom_par2 === NULL) { $nom_par2 = $NEL['1-99'][$par2]; if (($dizaine == 8) and ($NEL['huitante'] === 'octante')) { $nom_par2 = str_replace('huitante', 'octante', $nom_par2); } } # Après les dizaines et les unités, il reste à voir les centaines switch ($centaine) { case 0: return $nom_par2; case 1: return rtrim("cent {$nom_par2}"); } # Assertion : $centaine = 2 .. 9 $nom_centaine = $NEL['1-99'][$centaine]; if ($par2 == 0) return "{$nom_centaine} cents"; return "{$nom_centaine} cent {$nom_par2}"; } function enlettres_zilli($idx) { # Noms des 0ème à 9ème zillions static $petit = array( 'n', 'm', 'b', 'tr', 'quatr', 'quint', 'sext', 'sept', 'oct', 'non' ); # Composantes des 10ème à 999ème zillions static $unite = array( '<', 'un<', 'duo<', 'tredéci<', 'ms>viginti<', 'ns>triginta<', 'ns>quadraginta<', 'ns>quinquaginta<', 'né>sexaginta<', 'né>septuaginta<', 'mxs>octoginta<', 'é>nonaginta<' ); static $centaine = array( '>', 'nxs>cent', 'né>ducent', 'ns>trécent', 'ns>quadringent', 'ns>quingent', 'né>sescent', 'né>septingent', 'mxs>octingent', 'é>nongent' ); # Règles d'assimilation aux préfixes latins, modifiées pour accentuer # un éventuel 'é' de fin de préfixe. # (1) Si on trouve une lettre deux fois entre < > on la garde. # S'il y a plusieurs lettres dans ce cas, on garde la première. # (2) Sinon on efface tout ce qui est entre < >. # (3) On remplace "treé" par "tré", "seé" par "sé", "septeé" par "septé" # et "noveé" par "nové". # (4) En cas de dizaine sans centaine, on supprime la voyelle en trop. # Par exemple "déciilli" devient "décilli" et "trigintailli" devient # "trigintilli". # # Il est à noter que ces règles PERL (en particulier la première qui # est la plus complexe) sont *très* fortement inspirées du programme # de Nicolas Graner. On pourrait même parler de plagiat s'il n'avait # pas été au courant que je reprenais son code. # Voir # et # static $recherche = array( '/<[a-zé]*?([a-zé])[a-zé]*\1[a-zé]*>/', # (1) '/<[a-zé]*>/', # (2) '/eé/', # (3) '/[ai]illi/' # (4) ); static $remplace = array( '\\1', # (1) '', # (2) 'é', # (3) 'illi' # (4) ); $nom = ''; while ($idx > 0) { $p = $idx % 1000; $idx = floor($idx/1000); if ($p < 10) { $nom = $petit[$p] . 'illi' . $nom; } else { $nom = $unite[$p % 10] . $dizaine[floor($p/10) % 10] . $centaine[floor($p/100)] . 'illi' . $nom; } } return preg_replace($recherche, $remplace, $nom); } function enlettres_illions($idx) { global $NEL; if ($idx == 0) { return ''; } if ($NEL['zillions']) { return enlettres_zilli($idx) . 'ons'; } $suffixe = ''; while ($idx > $NEL['maxilli']) { $idx -= $NEL['maxilli']; $suffixe .= $NEL['de_maxillions']; } return "{$NEL['illi'][$idx]}illions{$suffixe}"; } function enlettres_avec_illiards($idx) { global $NEL; if ($idx == 0) return false; switch ($NEL['zilliard']) { case 0: return false; case 2: return true; } return ($idx == 1); } function enlettres($nombre, $options=NULL, $separateur=NULL) { global $NEL; if ($options !== NULL or $separateur !== NULL) { $NELsave = $NEL; enlettres_options($options, $separateur); $nom = enlettres($nombre); $NEL = $NELsave; return $nom; } # On ne garde que les chiffres, puis on supprime les 0 du début $nombre = preg_replace('/[^0-9]/', '', $nombre); $nombre = ltrim($nombre, '0'); if ($nombre == '') { if ($NEL['ordinal'] === 'nieme') return 'zéroïème'; else return 'zéro'; } $table_noms = array(); for ($idx = 0; $nombre != ''; $idx++) { $par6 = (int)((strlen($nombre) < 6) ? $nombre : substr($nombre, -6)); $nombre = substr($nombre, 0, -6); if ($par6 == 0) continue; $nom_par3_sup = enlettres_par3(floor($par6 / 1000)); $nom_par3_inf = enlettres_par3($par6 % 1000); $illions = enlettres_illions($idx); if (enlettres_avec_illiards($idx)) { if ($nom_par3_inf != '') { $table_noms[$illions] = $nom_par3_inf; } if ($nom_par3_sup != '') { $illiards = preg_replace('/illion/', 'illiard', $illions, 1); $table_noms[$illiards] = $nom_par3_sup; } } else { switch($nom_par3_sup) { case '': $nom_par6 = $nom_par3_inf; break; case 'un': $nom_par6 = rtrim("mille {$nom_par3_inf}"); break; default: $nom_par3_sup = preg_replace('/(vingt|cent)s/', '\\1', $nom_par3_sup); $nom_par6 = rtrim("{$nom_par3_sup} mille {$nom_par3_inf}"); break; } $table_noms[$illions] = $nom_par6; } } $nom_enlettres = ''; foreach ($table_noms as $nom => $nombre) { ## # $nombre est compris entre 'un' et # 'neuf cent nonante-neuf mille neuf cent nonante-neuf' # (ou variante avec 'quatre-vingt-dix-neuf') ## # $nom peut valoir '', 'millions', 'milliards', 'billions', ... # 'sextillions', 'sextilliards', 'millions de sextillions', # 'millions de sextilliards', etc. ## # Rectifications orthographiques de 1990 if ($NEL['rectif']) { $nombre = str_replace(' ', '-', $nombre); } # Nom (éventuel) et accord (éventuel) des substantifs $nom = rtrim("{$nombre} {$nom}"); if ($nombre == 'un') { # Un seul million, milliard, etc., donc au singulier # noter la limite de 1 remplacement, pour ne supprimer que le premier 's' # dans 'billions de sextillions de sextillions' $nom = preg_replace('/(illion|illiard)s/', '\\1', $nom, 1); } # Ajout d'un séparateur entre chaque partie if ($nom_enlettres == '') { $nom_enlettres = $nom; } else { $nom_enlettres = $nom . $NEL['separateur'] . $nom_enlettres; } } if ($NEL['ordinal'] === false) { # Nombre cardinal : le traitement est fini return $nom_enlettres; } # Aucun pluriel dans les ordinaux $nom_enlettres = preg_replace('/(cent|vingt|illion|illiard)s/', '\\1', $nom_enlettres); if ($NEL['ordinal'] !== 'nieme') { # Nombre ordinal simple (sans '-ième') return $nom_enlettres; } if ($nom_enlettres === 'un') { # Le féminin n'est pas traité ici. On fait la supposition # qu'il est plus facile de traiter ce cas à part plutôt # que de rajouter une option rien que pour ça. return 'premier'; } switch (substr($nom_enlettres, -1)) { case 'e': # quatre, onze à seize, trente à nonante, mille # exemple : quatre -> quatrième return substr($nom_enlettres, 0, -1) . 'ième'; case 'f': # neuf -> neuvième return substr($nom_enlettres, 0, -1) . 'vième'; case 'q': # cinq -> cinquième return $nom_enlettres . 'uième'; } # Tous les autres cas. # Exemples: deuxième, troisième, vingtième, trente et unième, # neuf centième, un millionième, quatre-vingt milliardième. return $nom_enlettres . 'ième'; } function enchiffres_petit($mot) { static $petit = array( # 1-16 'un' => 1, 'deux' => 2, 'trois' => 3, 'quatre' => 4, 'cinq' => 5, 'six' => 6, 'sept' => 7, 'huit' => 8, 'neuf' => 9, 'dix' => 10, 'onze' => 11, 'douze' => 12, 'treize' => 13, 'quatorze' => 14, 'quinze' => 15, 'seize' => 16, # 20-90 'vingt' => 20, 'vingts' => 20, 'trente' => 30, 'quarante' => 40, 'cinquante' => 50, 'soixante' => 60, 'septante' => 70, 'huitante' => 80, 'octante' => 80, 'nonante' => 90, # 100, 1000 'cent' => 100, 'cents' => 100, 'mil' => 1000, 'mille' => 1000 ); if (! isset($petit[$mot])) return false; return $petit[$mot]; } function enchiffres_zilli($mot) { # Noms des 0ème à 9ème zillions static $petits = array( 'n', 'm', 'b', 'tr', 'quadr', 'quint', 'sext', 'sept', 'oct', 'non' ); # Composantes des 10ème à 999ème zillions static $unites = array( '', 'un', 'duo', 'tre', 'quattuor', 'quin', 'se', 'septe', 'octo', 'nove' ); static $dizaines = array( '', 'dec', 'vigint', 'trigint', 'quadragint', 'quinquagint', 'sexagint', 'septuagint', 'octogint', 'nonagint' ); static $centaines = array( '', 'cent', 'ducent', 'trecent', 'quadringent', 'quingent', 'sescent', 'septingent', 'octingent', 'nongent' ); # Expressions rationnelles pour extraire les composantes static $um = '(|un|duo|tre(?!c)|quattuor|quin|se(?!p)(?!sc)|septe|octo|nove)[mnsx]?'; static $dm = '(|dec|(?:v|tr|quadr|quinqu|sex|septu|oct|non)[aio]gint)[ai]?'; static $cm = '(|(?:|du|tre|ses)cent|(?:quadri|qui|septi|octi|no)ngent)'; $u = array_search($mot, $petits); if ($u !== false) { return '00' . $u; } if (preg_match('/^'.$um.$dm.$cm.'$/', $mot, $resultat) < 1) { return false; } $u = array_search($resultat[1], $unites); $d = array_search($resultat[2], $dizaines); $c = array_search($resultat[3], $centaines); if ($u === false or $d === false or $c === false) { return false; } return $c.$d.$u; } function enchiffres_grand($mot) { # Quelques remplacements initiaux pour simplifier (les 'é' ont déjà # été tous transformés en 'e'). # (1) Je supprime le 's' final de '-illions' ou '-illiards' pour ne # tester que '-illion' ou '-illiard'. # (2) Les deux orthographes étant possibles pour quadrillion ou # quatrillion, je teste les deux. Noter que j'aurais pu changer # 'quadr' en 'quatr' au lieu de l'inverse, mais alors cela aurait # aussi changé 'quadragintillion' en 'quatragintillion', ce qui # n'est pas franchement le but recherché. # (3) En latin, on trouve parfois 'quatuor' au lieu de 'quattuor'. De même, # avec google on trouve quelques 'quatuordecillions' au milieu des # 'quattuordecillions' (environ 1 sur 10). # (4) La règle de John Conway et Allan Wechsler préconisait le préfixe # 'quinqua' au lieu de 'quin' que j'ai choisi. Pour accepter les deux, # je remplace 'quinqua' par 'quin', sauf dans 'quinquaginta' (50) # et dans 'quinquadraginta' (45). static $recherche = array( '/s$/', # (1) '/quatr/', # (2) '/quatuor/', # (3) '/quinqua(?!(dra)?gint)/' # (4) ); static $remplace = array( '', # (1) 'quadr', # (2) 'quattuor', # (3) 'quin' # (4) ); $mot = preg_replace($recherche, $remplace, $mot); if ($mot == 'millier') return 1; if ($mot == 'millinillion') return 2000; $prefixes = explode('illi', $mot); if (count($prefixes) < 2) { # Il faut au moins un 'illi' dans le nom return false; } switch (array_pop($prefixes)) { case 'on': # zillion : nombre pair de milliers $ard = 0; break; case 'ard': # zilliard : nombre impair de milliers $ard = 1; break; default: # Ce n'est ni un zillion, ni un zilliard return false; } $nombre = ''; foreach ($prefixes as $prefixe) { $par3 = enchiffres_zilli($prefixe); if ($par3 === false) return false; $nombre .= $par3; } if (strlen($nombre) > 3) { # On n'accepte que les nombres inférieurs au millinillion # pour limiter le temps de calcul return 0; } return 2*$nombre + $ard; } class enchiffres_struct { var $valeur; var $discr; function enchiffres_struct($mul, $val) { $this->valeur = $this->discr = $val; if ($mul != 0) { $this->valeur *= $mul; } } } function enchiffres_ajouter_petit(&$table_petits, $petit) { $somme = 0; while (($elem = array_pop($table_petits)) !== NULL) { if ($elem->discr > $petit) { array_push($table_petits, $elem); break; } $somme += $elem->valeur; } $elem = new enchiffres_struct($somme, $petit); array_push($table_petits, $elem); } function enchiffres_somme_petits($table_petits) { $somme = 0; foreach ($table_petits as $elem) { $somme += $elem->valeur; } return $somme; } function enchiffres_ajouter_grand(&$table_grands, $mantisse, $exposant) { while ($mantisse > 0) { if (isset($table_grands[$exposant])) { $mantisse += $table_grands[$exposant]; } $table_grands[$exposant] = $mantisse % 1000; $mantisse = floor($mantisse / 1000); $exposant++; } } function enchiffres($nom) { $nom = preg_replace('/[éèÉÈ]/', 'e', $nom); $nom = strtolower($nom); $table_mots = preg_split('/[^a-z]+/', $nom); $table_petits = array(); $mantisse = $exposant = 0; $table_grands = array(); foreach ($table_mots as $mot) { $petit = enchiffres_petit($mot); if ($petit !== false) { if ($mantisse != 0) { enchiffres_ajouter_grand($table_grands, $mantisse, $exposant); $mantisse = $exposant = 0; } enchiffres_ajouter_petit($table_petits, $petit); continue; } $grand = enchiffres_grand($mot); if ($grand === false) { # Ce n'est pas un nombre continue; } if ($grand == 0) { # Ce nombre était trop grand (millinillion et plus) : on annule le # tout pour limiter le temps de calcul. $mantisse = 0; $exposant = 0; $table_petits = array(); } else { if (count($table_petits) > 0) { $mantisse = enchiffres_somme_petits($table_petits); $exposant = 0; $table_petits = array(); } if ($mantisse != 0) { $exposant += $grand; } } } if (count($table_petits) > 0) { $mantisse = enchiffres_somme_petits($table_petits); $exposant = 0; } if ($mantisse != 0) { enchiffres_ajouter_grand($table_grands, $mantisse, $exposant); } $nombre = ""; for ($exposant = 0; count($table_grands) > 0; $exposant++) { if (isset($table_grands[$exposant])) { $par3 = $table_grands[$exposant]; unset($table_grands[$exposant]); } else { $par3 = 0; } $nombre = sprintf("%03d", $par3) . $nombre; } $nombre = ltrim($nombre, '0'); if ($nombre === '') $nombre = '0'; return $nombre; } function enchiffres_aerer($nombre, $blanc=' ', $virgule=',', $tranche=3) { # Si c'est un nombre à virgule, on traite séparément les deux parties if ($virgule !== NULL) { $ent_dec = preg_split("/$virgule/", $nombre); if (count($ent_dec) >= 2) { $ent = enchiffres_aerer($ent_dec[0], $blanc, NULL, $tranche); $dec = enchiffres_aerer($ent_dec[1], $blanc, NULL, -$tranche); return $ent . $virgule . $dec; } } # On ne garde que les chiffres $nombre = preg_replace('/[^0-9]/', '', $nombre); # Il est plus logique d'avoir un nombre positif pour les entiers, # donc négatif pour la partie décimale, mais plus pratique de # faire le contraire pour les substr(). $tranche = - (int)$tranche; if ($tranche == 0) { # on voulait juste supprimer les caractères en trop, pas en rajouter return $nombre; } $nombre_aere = ''; if ($tranche < 0) { # entier, ou partie entière d'un nombre décimal while ($nombre != '') { $par3 = substr($nombre, $tranche); $nombre = substr($nombre, 0, $tranche); if ($nombre_aere == '') { $nombre_aere = $par3; } else { $nombre_aere = $par3 . $blanc . $nombre_aere; } } } else { # partie décimale while ($nombre != '') { $par3 = substr($nombre, 0, $tranche); $nombre = substr($nombre, $tranche); if ($nombre_aere == '') { $nombre_aere = $par3; } else { $nombre_aere .= $blanc . $par3; } } } return $nombre_aere; } */ ?>