web-dev-qa-db-fra.com

Existe-t-il un moyen simple de convertir un nombre en un mot en PHP?

En PHP, existe-t-il un moyen simple de convertir un nombre en mot? Par exemple, 27 à vingt-sept .

35
Philip Morton

J'ai trouvé une partie (2007/2008) du code source en ligne et comme il est protégé par le droit d'auteur, mais je peux l'utiliser librement et le modifier à ma guise. Je le place donc ici et renouvelle la licence sous CC-Wiki:

<?php
/**
 * English Number Converter - Collection of PHP functions to convert a number
 *                            into English text.
 *
 * This exact code is licensed under CC-Wiki on Stackoverflow.
 * http://creativecommons.org/licenses/by-sa/3.0/
 *
 * @link     http://stackoverflow.com/q/277569/367456
 * @question Is there an easy way to convert a number to a Word in PHP?
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *
 *   Copyright 2007-2008 Brenton Fletcher. http://bloople.net/num2text
 *   You can use this freely and modify it however you want.
 */

function convertNumber($number)
{
    list($integer, $fraction) = explode(".", (string) $number);

    $output = "";

    if ($integer{0} == "-")
    {
        $output = "negative ";
        $integer    = ltrim($integer, "-");
    }
    else if ($integer{0} == "+")
    {
        $output = "positive ";
        $integer    = ltrim($integer, "+");
    }

    if ($integer{0} == "0")
    {
        $output .= "zero";
    }
    else
    {
        $integer = str_pad($integer, 36, "0", STR_PAD_LEFT);
        $group   = rtrim(chunk_split($integer, 3, " "), " ");
        $groups  = explode(" ", $group);

        $groups2 = array();
        foreach ($groups as $g)
        {
            $groups2[] = convertThreeDigit($g{0}, $g{1}, $g{2});
        }

        for ($z = 0; $z < count($groups2); $z++)
        {
            if ($groups2[$z] != "")
            {
                $output .= $groups2[$z] . convertGroup(11 - $z) . (
                        $z < 11
                        && !array_search('', array_slice($groups2, $z + 1, -1))
                        && $groups2[11] != ''
                        && $groups[11]{0} == '0'
                            ? " and "
                            : ", "
                    );
            }
        }

        $output = rtrim($output, ", ");
    }

    if ($fraction > 0)
    {
        $output .= " point";
        for ($i = 0; $i < strlen($fraction); $i++)
        {
            $output .= " " . convertDigit($fraction{$i});
        }
    }

    return $output;
}

function convertGroup($index)
{
    switch ($index)
    {
        case 11:
            return " decillion";
        case 10:
            return " nonillion";
        case 9:
            return " octillion";
        case 8:
            return " septillion";
        case 7:
            return " sextillion";
        case 6:
            return " quintrillion";
        case 5:
            return " quadrillion";
        case 4:
            return " trillion";
        case 3:
            return " billion";
        case 2:
            return " million";
        case 1:
            return " thousand";
        case 0:
            return "";
    }
}

function convertThreeDigit($digit1, $digit2, $digit3)
{
    $buffer = "";

    if ($digit1 == "0" && $digit2 == "0" && $digit3 == "0")
    {
        return "";
    }

    if ($digit1 != "0")
    {
        $buffer .= convertDigit($digit1) . " hundred";
        if ($digit2 != "0" || $digit3 != "0")
        {
            $buffer .= " and ";
        }
    }

    if ($digit2 != "0")
    {
        $buffer .= convertTwoDigit($digit2, $digit3);
    }
    else if ($digit3 != "0")
    {
        $buffer .= convertDigit($digit3);
    }

    return $buffer;
}

function convertTwoDigit($digit1, $digit2)
{
    if ($digit2 == "0")
    {
        switch ($digit1)
        {
            case "1":
                return "ten";
            case "2":
                return "twenty";
            case "3":
                return "thirty";
            case "4":
                return "forty";
            case "5":
                return "fifty";
            case "6":
                return "sixty";
            case "7":
                return "seventy";
            case "8":
                return "eighty";
            case "9":
                return "ninety";
        }
    } else if ($digit1 == "1")
    {
        switch ($digit2)
        {
            case "1":
                return "eleven";
            case "2":
                return "twelve";
            case "3":
                return "thirteen";
            case "4":
                return "fourteen";
            case "5":
                return "fifteen";
            case "6":
                return "sixteen";
            case "7":
                return "seventeen";
            case "8":
                return "eighteen";
            case "9":
                return "nineteen";
        }
    } else
    {
        $temp = convertDigit($digit2);
        switch ($digit1)
        {
            case "2":
                return "twenty-$temp";
            case "3":
                return "thirty-$temp";
            case "4":
                return "forty-$temp";
            case "5":
                return "fifty-$temp";
            case "6":
                return "sixty-$temp";
            case "7":
                return "seventy-$temp";
            case "8":
                return "eighty-$temp";
            case "9":
                return "ninety-$temp";
        }
    }
}

function convertDigit($digit)
{
    switch ($digit)
    {
        case "0":
            return "zero";
        case "1":
            return "one";
        case "2":
            return "two";
        case "3":
            return "three";
        case "4":
            return "four";
        case "5":
            return "five";
        case "6":
            return "six";
        case "7":
            return "seven";
        case "8":
            return "eight";
        case "9":
            return "nine";
    }
}
35
Chris

Vous pouvez également utiliser la classe NumberFormatter de intl package dans PHP. Voici un exemple de code pour vous aider à démarrer (pour la ligne de commande):

<?php
if ($argc < 3) 
    {
    echo "usage: php {$argv[0]} lang-tag number ...\n";
    exit;
    }

array_shift($argv);
$lang_tag = array_shift($argv);

$nf1 = new NumberFormatter($lang_tag, NumberFormatter::DECIMAL);
$nf2 = new NumberFormatter($lang_tag, NumberFormatter::SPELLOUT);

foreach ($argv as $num) 
    {
    echo $nf1->format($num).' is '.$nf2->format($num)."\n"; 
    }
28
user132513

Il y a le paquet Numbers_Words dans PECL. Il fait exactement ce que vous demandez. Les langues suivantes sont supportées:

  • bg (bulgare) de Kouber Saparev
  • cs (tchèque) de Petr 'PePa' Pavel
  • de (allemand) de Piotr Klaban
  • dk (danois) de Jesper Veggerby
  • en_100 (Donald Knuth system, anglais) de Piotr Klaban
  • en_GB (anglais britannique) par Piotr Klaban
  • en_US (anglais américain) par Piotr Klaban
  • es (espagnol Castellano) de Xavier Noguer
  • es_AR (espagnol argentin) de Martin Marrese
  • et (estonien) par Erkki Saarniit
  • fr de Kouber Saparev
  • fr_BE (Belgique française) par Kouber Saparev et Philippe Bajoit
  • il (hébreu) ​​de Hadar Porat
  • hu_HU (Hongrois) par Nils Homp
  • id (indonésien) d'Ernas M. Jamil et Arif Rifai Dwiyanto
  • it_IT (italien) de Filippo Beltramini et Davide Caironi
  • lt (lituanien) de Laurynas Butkus
  • nl (néerlandais) de WHAM van Dinter
  • pl (polonais) de Piotr Klaban
  • pt_BR (portugais brésilien) de Marcelo Subtil Marcal et Mario H.C.T.
  • ru (russe) de Andrey Demenev
  • sv (suédois) par Robin Ericsson
9
Milen A. Radev

J'ai réécrit le code ci-dessus pour l'adapter au format de numéro de mot écrit aux États-Unis.

function singledigit($number){
    switch($number){
        case 0:$Word = "zero";break;
        case 1:$Word = "one";break;
        case 2:$Word = "two";break;
        case 3:$Word = "three";break;
        case 4:$Word = "four";break;
        case 5:$Word = "five";break;
        case 6:$Word = "six";break;
        case 7:$Word = "seven";break;
        case 8:$Word = "eight";break;
        case 9:$Word = "nine";break;
    }
    return $Word;
}

function doubledigitnumber($number){
    if($number == 0){
        $Word = "";
    }
    else{
        $Word = "-".singledigit($number);
    }       
    return $Word;
}

function doubledigit($number){
    switch($number[0]){
        case 0:$Word = doubledigitnumber($number[1]);break;
        case 1:
            switch($number[1]){
                case 0:$Word = "ten";break;
                case 1:$Word = "eleven";break;
                case 2:$Word = "twelve";break;
                case 3:$Word = "thirteen";break;
                case 4:$Word = "fourteen";break;
                case 5:$Word = "fifteen";break;
                case 6:$Word = "sixteen";break;
                case 7:$Word = "seventeen";break;
                case 8:$Word = "eighteen";break;
                case 9:$Word = "ninteen";break;
            }break;
        case 2:$Word = "twenty".doubledigitnumber($number[1]);break;                
        case 3:$Word = "thirty".doubledigitnumber($number[1]);break;
        case 4:$Word = "forty".doubledigitnumber($number[1]);break;
        case 5:$Word = "fifty".doubledigitnumber($number[1]);break;
        case 6:$Word = "sixty".doubledigitnumber($number[1]);break;
        case 7:$Word = "seventy".doubledigitnumber($number[1]);break;
        case 8:$Word = "eighty".doubledigitnumber($number[1]);break;
        case 9:$Word = "ninety".doubledigitnumber($number[1]);break;

    }
    return $Word;
}

function unitdigit($numberlen,$number){
    switch($numberlen){         
        case 3:case 6:case 9:case 12:$Word = "hundred";break;
        case 4:case 5:$Word = "thousand";break;
        case 7:case 8:$Word = "million";break;
        case 10:case 11:$Word = "billion";break;
    }
    return $Word;
}

function numberToWord($number){

    $numberlength = strlen($number);
    if ($numberlength == 1) { 
        return singledigit($number);
    }elseif ($numberlength == 2) {
        return doubledigit($number);
    }
    else {

        $Word = "";
        $wordin = "";
        switch ($numberlength ) {
        case 5:case 8:  case 11:
            if($number[0] >0){
                $unitdigit = unitdigit($numberlength,$number[0]);
                $Word = doubledigit($number[0].$number[1]) ." ".$unitdigit." ";
                return $Word." ".numberToWord(substr($number,2));
            }
            else{
                return $Word." ".numberToWord(substr($number,1));
            }
        break;
        default:
            if($number[0] >0){
                $unitdigit = unitdigit($numberlength,$number[0]);
                $Word = singledigit($number[0]) ." ".$unitdigit." ";
            }               
            return $Word." ".numberToWord(substr($number,1));
        }
    }
}
2
wolfe

J'avais besoin d'une solution qui insère 'et' dans la chaîne renvoyée et la transforme en une phrase - généralement comme le dirait un humain. J'ai donc légèrement adapté une solution différente, publiée car je pensais que cela pourrait être utile à quelqu'un.

4,835,301 returns "Four million eight hundred and thirty five thousand three hundred and one."

Code

function convertNumber($num = false)
{
    $num = str_replace(array(',', ''), '' , trim($num));
    if(! $num) {
        return false;
    }
    $num = (int) $num;
    $words = array();
    $list1 = array('', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven',
        'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'
    );
    $list2 = array('', 'ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety', 'hundred');
    $list3 = array('', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion',
        'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion', 'quattuordecillion',
        'quindecillion', 'sexdecillion', 'septendecillion', 'octodecillion', 'novemdecillion', 'vigintillion'
    );
    $num_length = strlen($num);
    $levels = (int) (($num_length + 2) / 3);
    $max_length = $levels * 3;
    $num = substr('00' . $num, -$max_length);
    $num_levels = str_split($num, 3);
    for ($i = 0; $i < count($num_levels); $i++) {
        $levels--;
        $hundreds = (int) ($num_levels[$i] / 100);
        $hundreds = ($hundreds ? ' ' . $list1[$hundreds] . ' hundred' . ( $hundreds == 1 ? '' : '' ) . ' ' : '');
        $tens = (int) ($num_levels[$i] % 100);
        $singles = '';
        if ( $tens < 20 ) {
            $tens = ($tens ? ' and ' . $list1[$tens] . ' ' : '' );
        } elseif ($tens >= 20) {
            $tens = (int)($tens / 10);
            $tens = ' and ' . $list2[$tens] . ' ';
            $singles = (int) ($num_levels[$i] % 10);
            $singles = ' ' . $list1[$singles] . ' ';
        }
        $words[] = $hundreds . $tens . $singles . ( ( $levels && ( int ) ( $num_levels[$i] ) ) ? ' ' . $list3[$levels] . ' ' : '' );
    } //end for loop
    $commas = count($words);
    if ($commas > 1) {
        $commas = $commas - 1;
    }
    $words = implode(' ',  $words);
    $words = preg_replace('/^\s\b(and)/', '', $words );
    $words = trim($words);
    $words = ucfirst($words);
    $words = $words . ".";
    return $words;
}
2
prikkles

En utilisant la classe NumberFormatter, il est simple d’obtenir une conversion en mots.

<?php

$number = '12345';
$locale = 'en_US';
$fmt = numfmt_create($locale, NumberFormatter::SPELLOUT);
$in_words = numfmt_format($fmt, $number);

print_r($in_words);
// twelve thousand three hundred forty-five

?>
1
Mohammed Shamshid

Vous pouvez utiliser la classe NumberFormatter Class :

$f = new NumberFormatter("en", NumberFormatter::SPELLOUT);
echo $f->format($myNumber);
0
Rohan kumar

Voici un petit cours que j'ai écrit ce soir. Mises en garde:

  1. Seulement en anglais.
  2. Ne gère que les définitions américaines/françaises de milliards, etc.
  3. La méthode longform ne gère pas les décimales. Cela les efface. N'hésitez pas à modifier cela et à ajouter cette fonctionnalité si vous le souhaitez. 
  4. La méthode numberformat fait des décimales, mais n’arrondit pas. J'ai dû créer une nouvelle fonction numberformat en raison des limitations inhérentes à PHP avec les tailles entières. Je traduisais tellement de chiffres que lorsque j'ai utilisé number_format() pour vérifier mes traductions, il m'a fallu 30 minutes pour comprendre que mes traductions n'étaient pas fausses, mais number_format l'était. 
  5. Ce n'est pas une mise en garde à propos de la classe, mais à propos de PHP. Les versions 32 bits de PHP ne gèrent pas les entiers supérieurs à 2,147,483,647 (2 milliards et plus). Les versions 64 bits gèrent jusqu'à 9 quintillion ou quelque chose du genre. MAIS cela n’a aucune importance ici tant que vous insérez les nombres dans la méthode longform sous la forme string. J'ai composé un nombre correct à 306 chiffres sur ajax à partir d'un formulaire Web, à condition que je le transmette au serveur sous la forme ''+number

Ainsi, cette classe traduira des nombres allant jusqu’à 999 Centillion, 999 etc. (une chaîne de 9 306 caractères, par exemple). N'importe quel nombre supérieur à cela et la fonction ne fait que renvoyer un message muet. 

Usage: 

$number = '999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999';
reallyBig::longform($number);

Le deuxième paramètre optionnel boolean est défini par défaut sur true, ce qui ajoute des virgules du mieux qu’il peut au bon endroit, afin de rendre le nombre plus lisible. 

En passant, vous pouvez mettre un - au début si vous voulez que ce soit négatif, mais tous les autres caractères inclus dans la chaîne entrée seront supprimés. Par exemple:

reallyBig::longform('-C55LL-M5-4-a-9u7-71m3-M8'); affichera: negative five billion, five hundred fifty-four million, nine hundred seventy-seven thousand, one hundred thirty-eight

La méthode numberformat n'est nécessaire pour aucune autre méthode. C'est juste là si vous voulez vérifier un nombre traduit très long. Étant donné que toutes ces fonctions traitent les nombres comme des chaînes, elles ne se heurtent pas aux limites de PHP. 

La seule raison pour laquelle j'ai arrêté à 999 centillions, c'est parce que centillion était le dernier chiffre du site Web que je cherchais alors que je ne me souvenais plus de ce qui arrivait après un décillion. 

class reallyBig
{
    private static $map, $strings;
    private static function map()
    {
        $map = array();
        $num = 1;
        $count = 1;
        while($num < 307)
        {
            if($count == 1) $map[$num] = $num+2;
            elseif($count == 2) $map[$num] = $num+1;
            else 
            {
                $map[$num] = $num;
                $count = 0;
            }
            $count++;
            $num++;
        }
        return $map;
    }
    private static function strings()
    {
        return array 
        (
            6 => 'thousand',
            9 => 'million',
            12 => 'billion',
            15 => 'trillion',
            18 => 'quadrillion',
            21 => 'quintillion',
            24 => 'sextillion',
            27 => 'septillion',
            30 => 'octillion',
            33 => 'nonillion',
            36 => 'decillion',
            39 => 'undecillion',
            42 => 'duodecillion',
            45 => 'tredecillion',
            48 => 'quattuordecillion',
            51 => 'quindecillion',
            54 => 'sexdecillion',
            57 => 'septendecillion',
            60 => 'octodecillion',
            63 => 'novemdecillion',
            66 => 'vigintillion',
            69 => 'unvigintillion',
            72 => 'duovigintillion',
            75 => 'trevigintillion',
            78 => 'quattuorvigintillion',
            81 => 'quinvigintillion',
            84 => 'sexvigintillion',
            87 => 'septenvigintillion',
            90 => 'octovigintillion',
            93 => 'novemvigintillion',
            96 => 'trigintillion',
            99 => 'untrigintillion',
            102 => 'duotrigintillion',
            105 => 'tretrigintillion',
            108 => 'quattuortrigintillion',
            111 => 'quintrigintillion',
            114 => 'sextrigintillion',
            117 => 'septentrigintillion',
            120 => 'octotrigintillion',
            123 => 'novemtrigintillion',
            126 => 'quadragintillion',
            129 => 'unquadragintillion',
            132 => 'duoquadragintillion',
            135 => 'trequadragintillion',
            138 => 'quattuorquadragintillion',
            141 => 'quinquadragintillion',
            144 => 'sexquadragintillion',
            147 => 'septenquadragintillion',
            150 => 'octoquadragintillion',
            153 => 'novemquadragintillion',
            156 => 'quinquagintillion',
            159 => 'unquinquagintillion',
            162 => 'duoquinquagintillion',
            165 => 'trequinquagintillion',
            168 => 'quattuorquinquagintillion',
            171 => 'quinquinquagintillion',
            174 => 'sexquinquagintillion',
            177 => 'septenquinquagintillion',
            180 => 'octoquinquagintillion',
            183 => 'novemquinquagintillion',
            186 => 'sexagintillion',
            189 => 'unsexagintillion',
            192 => 'duosexagintillion',
            195 => 'tresexagintillion',
            198 => 'quattuorsexagintillion',
            201 => 'quinsexagintillion',
            204 => 'sexsexagintillion',
            207 => 'septensexagintillion',
            210 => 'octosexagintillion',
            213 => 'novemsexagintillion',
            216 => 'septuagintillion',
            219 => 'unseptuagintillion',
            222 => 'duoseptuagintillion',
            225 => 'treseptuagintillion',
            228 => 'quattuorseptuagintillion',
            231 => 'quinseptuagintillion',
            234 => 'sexseptuagintillion',
            237 => 'septenseptuagintillion',
            240 => 'octoseptuagintillion',
            243 => 'novemseptuagintillion',
            246 => 'octogintillion',
            249 => 'unoctogintillion',
            252 => 'duooctogintillion',
            255 => 'treoctogintillion',
            258 => 'quattuoroctogintillion',
            261 => 'quinoctogintillion',
            264 => 'sexoctogintillion',
            267 => 'septenoctogintillion',
            270 => 'octooctogintillion',
            273 => 'novemoctogintillion',
            276 => 'nonagintillion',
            279 => 'unnonagintillion',
            282 => 'duononagintillion',
            285 => 'trenonagintillion',
            288 => 'quattuornonagintillion',
            291 => 'quinnonagintillion',
            294 => 'sexnonagintillion',
            297 => 'septennonagintillion',
            300 => 'octononagintillion',
            303 => 'novemnonagintillion',
            306 => 'centillion',
        );
    }
    public static function longform($number = string, $commas = true)
    {
        $negative = substr($number, 0, 1) == '-' ? 'negative ' : '';
        list($number) = explode('.', $number);          
        $number = trim(preg_replace("/[^0-9]/u", "", $number));
        $number = (string)(ltrim($number,'0'));
        if(empty($number)) return 'zero';
        $length = strlen($number);
        if($length <  2) return $negative.self::ones($number);
        if($length <  3) return $negative.self::tens($number);
        if($length <  4) return $commas ? $negative.str_replace('hundred ', 'hundred and ', self::hundreds($number)) : $negative.self::hundreds($number);
        if($length < 307) 
        {
            self::$map = self::map();
            self::$strings = self::strings();
            $result = self::beyond($number, self::$map[$length]);
            if(!$commas) return $negative.$result;
            $strings = self::$strings;
            $thousand = array_shift($strings);
            foreach($strings as $string) $result = str_replace($string.' ', $string.', ', $result);
            if(strpos($result, 'thousand') !== false) list($junk,$remainder) = explode('thousand', $result);
            else $remainder = $result;
            return strpos($remainder, 'hundred') !== false ? $negative.str_replace('thousand ', 'thousand, ', $result) : $negative.str_replace('thousand ', 'thousand and ', $result);
        }
        return 'a '.$negative.'number too big for your britches';
    }
    private static function ones($number)
    {
        $ones = array('zero','one','two','three','four','five','six','seven','eight','nine');
        return $ones[$number];
    }
    private static function tens($number)
    {
        $number = (string)(ltrim($number,'0'));
        if(strlen($number) < 2) return self::ones($number);
        if($number < 20)
        {
            $teens = array('ten','eleven','twelve','thirteen','fourteen','fifteen','sixteen','seventeen','eighteen','nineteen');
            return $teens[($number-10)];
        }
        else
        {
            $tens = array('','','twenty','thirty','forty','fifty','sixty','seventy','eighty','ninety');
            $Word = $tens[$number[0]];
            return empty($number[1]) ? $Word : $Word.'-'.self::ones($number[1]);
        }
    }
    private static function hundreds($number)
    {
        $number = (string)(ltrim($number,'0'));
        if(strlen($number) < 3) return self::tens($number);
        $Word = self::ones($number[0]).' hundred';
        $remainder = substr($number, -2);
        if(ltrim($remainder,'0') != '') $Word .= ' '.self::tens($remainder);
        return $Word;
    }
    private static function beyond($number, $limit)
    {
        $number = (string)(ltrim($number,'0'));
        $length = strlen($number);
        if($length < 4) return self::hundreds($number);
        if($length < ($limit-2)) return self::beyond($number, self::$map[($limit-3)]);
        if($length == $limit) $Word = self::hundreds(substr($number, 0, 3), true);
        elseif($length == ($limit-1)) $Word = self::tens(substr($number, 0, 2));
        else $Word = self::ones($number[0]);
        $Word .= ' '.self::$strings[$limit];
        $sub = ($limit-3);
        $remainder = substr($number, -$sub);
        if(ltrim($remainder,'0') != '') $Word .= ' '.self::beyond($remainder, self::$map[$sub]);
        return $Word;
    }
    public static function numberformat($number, $fixed = 0, $dec = '.', $thou = ',')
    {
        $negative = substr($number, 0, 1) == '-' ? '-' : '';
        $number = trim(preg_replace("/[^0-9\.]/u", "", $number));
        $number = (string)(ltrim($number,'0'));
        $fixed = (int)$fixed;
        if(!is_numeric($fixed)) $fixed = 0;
        if(strpos($number, $dec) !== false) list($number,$decimals) = explode($dec, $number); 
        else $decimals = '0';
        if($fixed) $decimals = '.'.str_pad(substr($decimals, 0, $fixed), $fixed, 0, STR_PAD_RIGHT);
        else $decimals = '';
        $thousands = array_map('strrev', array_reverse(str_split(strrev($number), 3)));
        return $negative.implode($thou,$thousands).$decimals;
    }
}
0
Works for a Living