Programowanie w języku PHP » FAQ

Jak zamienić liczbę na jej postać słowną

  • 9 komentarzy
  • 8293 odsłony
  • Oceń ten tekst jako pierwszy
Aby zamienić liczbę na jej słowną postać możesz skorzystać z funkcji mojego autorstwa zamieszczonych poniżej:

<?php
 
if(!function_exists('str_split')){
  function str_split($string,$len = 1) {
        if ($len < 1) return false;
    for($i=0, $rt = Array();$i<ceil(strlen($string)/$len);$i++) 
      $rt[$i] = substr($string, $len*$i, $len); 
    return($rt);
  } 
}
 
$slowa = Array(
  'minus',
 
  Array(
    'zero',
    'jeden',
    'dwa',
    'trzy',
    'cztery',
    'pięć',
    'sześć',
    'siedem',
    'osiem',
    'dziewięć'),
 
  Array(
    'dziesięć',
    'jedenaście',
    'dwanaście',
    'trzynaście',
    'czternaście',
    'piętnaście',
    'szesnaście',
    'siedemnaście',
    'osiemnaście',
    'dziewiętnaście'),
 
  Array(
    'dziesięć',
    'dwadzieścia',
    'trzydzieści',
    'czterdzieści',
    'pięćdziesiąt',
    'sześćdziesiąt',
    'siedemdziesiąt',
    'osiemdziesiąt',
    'dziewięćdziesiąt'),
 
  Array(
    'sto',
    'dwieście',
    'trzysta',
    'czterysta',
    'pięćset',
    'sześćset',
    'siedemset',
    'osiemset',
    'dziewięćset'),
 
  Array(
    'tysiąc',
    'tysiące',
    'tysięcy'),
 
  Array(
    'milion',
    'miliony',
    'milionów'),
 
  Array(
    'miliard',
    'miliardy',
    'miliardów'),
 
  Array(
    'bilion',
    'biliony',
    'bilionów'),
 
  Array(
    'biliard',
    'biliardy',
    'biliardów'),
 
  Array(
    'trylion',
    'tryliony',
    'trylionów'),
 
  Array(
    'tryliard',
    'tryliardy',
    'tryliardów'),
 
  Array(
    'kwadrylion',
    'kwadryliony',
    'kwadrylionów'),
 
  Array(
    'kwintylion',
    'kwintyliony',
    'kwintylionów'),
 
  Array(
    'sekstylion',
    'sekstyliony',
    'sekstylionów'),
 
  Array(
    'septylion',
    'septyliony',
    'septylionów'),
 
  Array(
    'oktylion',
    'oktyliony',
    'oktylionów'),
 
  Array(
    'nonylion',
    'nonyliony',
    'nonylionów'),
 
  Array(
    'decylion',
    'decyliony',
    'decylionów')
);
 
function odmiana($odmiany, $int){ // $odmiany = Array('jeden','dwa','pięć')
  $txt = $odmiany[2];
  if ($int == 1) $txt = $odmiany[0];
  $jednosci = (int) substr($int,-1);
  $reszta = $int % 100;
  if (($jednosci > 1 && $jednosci < 5) &! ($reszta > 10 && $reszta < 20))
    $txt = $odmiany[1];
  return $txt;
}
 
function liczba($int){ // odmiana dla liczb < 1000
  global $slowa;
  $wynik = '';
  $j = abs((int) $int);
 
  if ($j == 0) return $slowa[1][0];
  $jednosci = $j % 10;
  $dziesiatki = ($j % 100 - $jednosci) / 10;
  $setki = ($j - $dziesiatki*10 - $jednosci) / 100;
 
  if ($setki > 0) $wynik .= $slowa[4][$setki-1].' ';
 
  if ($dziesiatki > 0)
        if ($dziesiatki == 1) $wynik .= $slowa[2][$jednosci].' ';
  else
    $wynik .= $slowa[3][$dziesiatki-1].' ';
 
  if ($jednosci > 0 && $dziesiatki != 1) $wynik .= $slowa[1][$jednosci].' ';
  return $wynik;
}
 
function slownie($int){
 
  global $slowa;
 
  $in = preg_replace('/[^-\d]+/','',$int);
  $out = '';
 
  if ($in{0} == '-'){
    $in = substr($in, 1);
    $out = $slowa[0].' ';
  }
 
  $txt = str_split(strrev($in), 3);
 
  if ($in == 0) $out = $slowa[1][0].' ';
 
  for ($i = count($txt) - 1; $i >= 0; $i--){
    $liczba = (int) strrev($txt[$i]);
    if ($liczba > 0)
      if ($i == 0)
        $out .= liczba($liczba).' ';
          else
        $out .= ($liczba > 1 ? liczba($liczba).' ' : '')
          .odmiana( $slowa[4 + $i], $liczba).' ';
  }
  return trim($out);
}
 
?>


poniżej przedstawiam krótki opis tych funkcji:

str_split - implementacja funkcji str_split dla PHP w wersji <5.0

odmiana - funkcja odmienia wybrane słowo w danej liczbie, ma składnię:
    odmiana(Array('jeden','dwa','pięć'),liczba);

Przykład:
<?php
echo '16 '.odmiana(Array('punkt','punkty','punktów'),16); // 16 punktów
echo '103 '.odmiana(Array('ciastko','ciastka','ciastek'),103); // 103 ciastka
?>


liczba - przedstawienie słownej postaci dla liczb trzycyfrowych (mniejszych niż 1000) - korzysta ze zdefiniowanej wyżej globalnej tablicy "$slowa"

slownie - główna funkcja zamieniająca dowolną liczbę na jej postać słowną - korzysta ze wszystkich wyżej zdefiniowanych procedur

Przykład:
<?php
echo slownie('14902');
 // czternaście tysięcy dziewięćset dwa
echo slownie('16504616');
 // szesnaście milionów pięćset cztery tysiące sześćset szesnaście
 
?>


Przykład:
<?php
 
for($i = -10; $i < 50; $i++)
  echo slownie($i*abs($i)).'<br>';
 
?>


zwraca:

minus sto minus osiemdziesiąt jeden minus sześćdziesiąt cztery minus czterdzieści dziewięć minus trzydzieści sześć minus dwadzieścia pięć minus szesnaście minus dziewięć minus cztery minus jeden zero jeden cztery dziewięć szesnaście dwadzieścia pięć trzydzieści sześć czterdzieści dziewięć sześćdziesiąt cztery osiemdziesiąt jeden

sto sto dwadzieścia jeden sto czterdzieści cztery sto sześćdziesiąt dziewięć sto dziewięćdziesiąt sześć dwieście dwadzieścia pięć dwieście pięćdziesiąt sześć dwieście osiemdziesiąt dziewięć trzysta dwadzieścia cztery trzysta sześćdziesiąt jeden czterysta czterysta czterdzieści jeden czterysta osiemdziesiąt cztery pięćset dwadzieścia dziewięć pięćset siedemdziesiąt sześć sześćset dwadzieścia pięć sześćset siedemdziesiąt sześć siedemset dwadzieścia dziewięć siedemset osiemdziesiąt cztery osiemset czterdzieści jeden

dziewięćset dziewięćset sześćdziesiąt jeden tysiąc dwadzieścia cztery tysiąc osiemdziesiąt dziewięć tysiąc sto pięćdziesiąt sześć tysiąc dwieście dwadzieścia pięć tysiąc dwieście dziewięćdziesiąt sześć tysiąc trzysta sześćdziesiąt dziewięć tysiąc czterysta czterdzieści cztery tysiąc pięćset dwadzieścia jeden tysiąc sześćset tysiąc sześćset osiemdziesiąt jeden tysiąc siedemset sześćdziesiąt cztery tysiąc osiemset czterdzieści dziewięć tysiąc dziewięćset trzydzieści sześć dwa tysiące dwadzieścia pięć dwa tysiące sto szesnaście dwa tysiące dwieście dziewięć dwa tysiące trzysta cztery dwa tysiące czterysta jeden




Uwaga ! Funkcja slownie przyjmuje jako parametr zarówno typ string jak i integer ale typ integer jest ograniczony wielkością w języku PHP więc kod:
echo slownie('999100098645123001002008016078123112114456026');

zwróci:

dziewięćset dziewięćdziesiąt dziewięć decylionów sto nonylionów dziewięćdziesiąt osiem oktylionów sześćset czterdzieści pięć septylionów sto dwadzieścia trzy sekstyliony kwintylion dwa kwadryliony osiem tryliardów szesnaście trylionów siedemdziesiąt osiem biliardów sto dwadzieścia trzy biliony sto dwanaście miliardów sto czternaście milionów czterysta pięćdziesiąt sześć tysięcy dwadzieścia sześć


natomiast kod:
echo slownie(999100098645123001002008016078123112114456026);

(czyli to samo tylko bez cudzysłowów) zwróci w PHP 4.3:

dziewięćdziesiąt dziewięć biliardów dziewięćset dziesięć bilionów dziewięć miliardów osiemset sześćdziesiąt cztery miliony pięćset dwanaście tysięcy czterdzieści cztery

9 komentarzy

Wojciech Grzeszkiewicz 2016-03-04 15:47

Po 11 latach ten artykuł wymaga aktualizacji na nowożytną wersję tego skryptu. Musiałem poświęcić chwilę aby doprowadzić go do używalności w moim projekcie Symfony 2.7 - zamieszczam tutaj aby oszczędzić Wam czasu. Klasa dodatkowo rozszerzona o możliwość zamiany kwot w złotych lub dowolnej innej walucie (razem z groszami) na wersję słowną. Klasa zgodna z PHP 5.4, PHPdoc oraz standardem PSR-2 (przechodzi testy code sniffer).

<?php
/**
 * Created by PhpStorm.
 * User: wgrzeszkiewicz
 * Date: 04.03.16
 * Time: 14:11
 */
 
namespace Master\Bundle\CoreBundle\Tools;
 
/**
 * Class NumberInWords
 * @package Master\Bundle\CoreBundle\Tools
 *
 * Wzorowane na:
 * @see http://4programmers.net/PHP/FAQ/Jak_zamieni%C4%87_liczb%C4%99_na_jej_posta%C4%87_s%C5%82own%C4%85_
 */
class NumberInWords
{
    /**
     * @var array
     */
    protected static $words = [
        'minus',
        ['zero', 'jeden', 'dwa', 'trzy', 'cztery', 'pięć', 'sześć', 'siedem', 'osiem', 'dziewięć'],
        ['dziesięć', 'jedenaście', 'dwanaście', 'trzynaście', 'czternaście', 'piętnaście', 'szesnaście', 'siedemnaście', 'osiemnaście', 'dziewiętnaście'],
        ['dziesięć', 'dwadzieścia', 'trzydzieści', 'czterdzieści', 'pięćdziesiąt', 'sześćdziesiąt', 'siedemdziesiąt', 'osiemdziesiąt', 'dziewięćdziesiąt'],
        ['sto', 'dwieście', 'trzysta', 'czterysta', 'pięćset', 'sześćset', 'siedemset', 'osiemset', 'dziewięćset'],
        ['tysiąc', 'tysiące', 'tysięcy'],
        ['milion', 'miliony', 'milionów'],
        ['miliard', 'miliardy', 'miliardów'],
        ['bilion', 'biliony', 'bilionów'],
        ['biliard', 'biliardy', 'biliardów'],
        ['trylion', 'tryliony', 'trylionów'],
        ['tryliard', 'tryliardy', 'tryliardów'],
        ['kwadrylion', 'kwadryliony', 'kwadrylionów'],
        ['kwintylion', 'kwintyliony', 'kwintylionów'],
        ['sekstylion', 'sekstyliony', 'sekstylionów'],
        ['septylion', 'septyliony', 'septylionów'],
        ['oktylion', 'oktyliony', 'oktylionów'],
        ['nonylion', 'nonyliony', 'nonylionów'],
        ['decylion', 'decyliony', 'decylionów']
    ];
 
    /**
     * Podaje słowną wartość liczby całkowitej (równierz podaną w postaci stringa)
     *
     * @param integer $int
     * @return string
     */
    public static function integerNumberToWords($int)
    {
        $int = strval($int);
        $in = preg_replace('/[^-\d]+/', '', $int);
 
        $return = '';
 
        if ($in{0} == '-') {
            $in = substr($in, 1);
            $return = self::$words[0] . ' ';
        }
 
        $txt = str_split(strrev($in), 3);
 
        if ($in == 0) {
            $return = self::$words[1][0] . ' ';
        }
 
        for ($i = count($txt) - 1; $i >= 0; $i--) {
            $number = (int) strrev($txt[$i]);
 
            if ($number > 0) {
                if ($i == 0) {
                    $return .= self::number($number) . ' ';
                } else {
                    $return .= ($number > 1 ? self::number($number) . ' ' : '')
                            . self::inflection(self::$words[4 + $i], $number) . ' ';
                }
            }
        }
 
        return self::clear($return);
    }
 
    /**
     * Podaje słowną wartość kwoty wraz z wartościami po kropce.
     * Nie przyjmuje wartości przedzielonych przecinkami (jako wartości nie numerycznych).
     *
     * @param integer|string $amount
     * @param string $currencyName
     * @param string $centName
     * @return string
     * @throws \Exception
     */
    public static function amountToWords($amount, $currencyName = 'zł', $centName = 'gr')
    {
        if (!is_numeric($amount)) {
            throw new \Exception('Nieprawidłowa kwota');
        }
 
        $amountString = number_format($amount, 2, '.', '');
        list($bigAmount, $smallAmount) = explode('.', $amountString);
 
        $bigAmount = static::integerNumberToWords($bigAmount) . ' ' . $currencyName . ' ';
        $smallAmount = static::integerNumberToWords($smallAmount) . ' ' . $centName;
 
        return self::clear($bigAmount . $smallAmount);
    }
 
    /**
     * Czyści podwójne spacje i trimuje
     *
     * @param $string
     * @return mixed
     */
    protected static function clear($string)
    {
        return preg_replace('!\s+!', ' ', trim($string));
    }
 
    /**
     * $inflections = Array('jeden','dwa','pięć')
     *
     * @param string[] $inflections
     * @param $int
     * @return mixed
     */
    protected static function inflection(array $inflections, $int)
    {
        $txt = $inflections[2];
 
        if ($int == 1) {
            $txt = $inflections[0];
        }
 
        $units = intval(substr($int, -1));
 
        $rest = $int % 100;
 
        if (($units > 1 && $units < 5) &! ($rest > 10 && $rest < 20)) {
            $txt = $inflections[1];
        }
 
        return $txt;
    }
 
    /**
     * Odmiana dla liczb < 1000
     *
     * @param integer $int
     * @return string
     */
    protected static function number($int)
    {
        $return = '';
 
        $j = abs(intval($int));
 
        if ($j == 0) {
            return self::$words[1][0];
        }
 
        $units = $j % 10;
        $dozens = intval(($j % 100 - $units) / 10);
        $hundreds = intval(($j - $dozens * 10 - $units) / 100);
 
        if ($hundreds > 0) {
            $return .= self::$words[4][$hundreds - 1] . ' ';
        }
 
        if ($dozens > 0) {
            if ($dozens == 1) {
                $return .= self::$words[2][$units] . ' ';
            } else {
                $return .= self::$words[3][$dozens - 1] . ' ';
            }
        }
 
        if ($units > 0 && $dozens != 1) {
            $return .= self::$words[1][$units] . ' ';
        }
 
        return $return;
    }
}


Użycie banalne:

echo NumberInWords::integerNumberToWords(921) . PHP_EOL;
echo NumberInWords::integerNumberToWords('921') . PHP_EOL;
echo NumberInWords::amountToWords(921.24) . PHP_EOL;
echo NumberInWords::amountToWords('921.24') . PHP_EOL;

betatester 2013-09-28 21:59

Dobra teraz moja kolej, tutaj napisałem biblioteczkę do robienia tego...
https://bitbucket.org/stopsopa/kwotaslownie
miłej zabawy...

salvi 2008-10-21 12:17

Ja używam tego skryptu do generowania sobie faktur więc z liczbami typu miliard i większymi nie mam problemów :-). Zresztą z milionami też nie... :-)

grzegorznowak 2010-06-09 16:51

świetne. Szybka przeróbka na obiektowatość i będzie jak znalazł -)
Dzięki za udostępnienie !

Adamo 2006-08-19 11:08

aby przedstawić słownie kwotę można dodać jeszcze tą funkcję:

function kwotaslownie($kwota){
  $kwota = explode(',', $kwota);
 
  $zl = preg_replace('/[^-\d]+/','', $kwota[0]);
  $gr = preg_replace('/[^\d]+/','', substr(isset($kwota[1]) ? $kwota[1] : 0, 0, 2));
  while(strlen($gr) < 2) $gr .= '0';
 
  echo slownie($zl) . ' ' . odmiana(Array('złoty', 'złote', 'złotych'), $zl) .
      (intval($gr) == 0 ? '' :
      ' ' . slownie($gr) . ' ' . odmiana(Array('grosz', 'grosze', 'groszy'), $gr));
}
 
echo kwotaslownie('502,15');


chyba tłumaczenie zbędne ?

Adam.Pilorz 2005-09-11 15:20

Te nieporozumienia wynikają stąd, że po prostu w polsce inaczej to się nazywa niż na świecie. Po prostu po angielsku bilion to jest po polsku miliard, po angielsku trilion to jest polski bilion itp. itd. (Z tego co wiem ;) )

Adamo 2005-09-11 00:02

hmm, czytałem dużo o tych dużych liczbach przed zamieszczeniem i oficjalnie wyczytałem bo potwierdzało się to w największej liczbie źródeł że w polsce się dobrze przyjęło z "jard'ów" liczby miliard, biliard, triliard, ale też jeszcze ludzie chyba się dobrze nie zgadali bo napisane było że największą liczbą którą można używać bez nieporozumień jest milion w europie, a miliard w polsce - tak czy owak każdy może sobie łatwo zmienić na tak jak będzie chciał ;P

AklimX 2005-09-10 15:09

cool, ale czemu pominąłeś kwadryliard, kwintyliard, sekstyliard i tak dalej?
http://pl.wikipedia.org/wiki/Nazwy_du%C5%BCych_liczb

Adam.Pilorz 2005-09-09 00:45

Nie testowałem, ale imponujące. I ładnie opisane, a zarazem krótko (bo to FAQ nie Art) - ogólnie - wszystko jak być powinno.