Jak zamienić liczbę na jej postać słowną? (Język Polski)

Adamo

Aby zamienić liczbę na jej słowną postać możesz skorzystać z funkcji mojego autorstwa zamieszczonych poniżej:

<?php
$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:

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: ```php 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

10 komentarzy

Hmm, próbowałam kodów zamieszczonych tutaj ale nie wyrzuciły mi słownej reprezentacji. Ma ktoś jakiś update?

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;

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

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... :-)

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

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 ?

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 ;) )

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

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

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