Слава Україні!

Преобразование числа в текст на php

Функции и классы на php для преобразования чисел в текст
27-го січня 2012, 4:01

1. Функция


    /**
    * Возвращает сумму прописью
    * @uses morph(...)
    */

    public function num2str($num) {
        $nul='ноль';
        $ten=array(
            array('','один','два','три','четыре','пять','шесть','семь', 'восемь','девять'),
            array('','одна','две','три','четыре','пять','шесть','семь', 'восемь','девять'),
        );
        $a20 = array('десять','одиннадцать','двенадцать','тринадцать','четырнадцать','пятнадцать','шестнадцать','семнадцать','восемнадцать','девятнадцать');
        $tens = array(2=>'двадцать','тридцать','сорок','пятьдесят','шестьдесят','семьдесят' ,'восемьдесят','девяносто');
        $hundred=array('','сто','двести','триста','четыреста','пятьсот','шестьсот', 'семьсот','восемьсот','девятьсот');
        $unit = array( // Units
            array('копейка' ,'копейки' ,'копеек'    ,1),
            array('рубль'   ,'рубля'   ,'рублей'    ,0),
            array('тысяча'  ,'тысячи'  ,'тысяч'     ,1),
            array('миллион' ,'миллиона','миллионов' ,0),
            array('миллиард','милиарда','миллиардов',0),
        );
        //
        list($rub,$kop) = explode('.', sprintf("%015.2f", floatval($num)));
        $out = array();
        if (intval($rub)>0) {
            foreach(str_split($rub,3) as $uk=>$v) { // by 3 symbols
                if (!intval($v)) continue;
                $uk = sizeof($unit)-$uk-1; // unit key
                $gender = $unit[$uk][3];
                list($i1,$i2,$i3) = array_map('intval',str_split($v,1));
                // mega-logic
                $out[] = $hundred[$i1]; # 1xx-9xx
                if ($i2>1) $out[]= $tens[$i2].' '.$ten[$gender][$i3]; # 20-99
                else $out[]= $i2>0 ? $a20[$i3] : $ten[$gender][$i3]; # 10-19 | 1-9
                // units without rub & kop
                if ($uk>1) $out[]= morph($v,$unit[$uk][0],$unit[$uk][1],$unit[$uk][2]);
            } //foreach
        }
        else $out[] = $nul;
        $out[] = morph(intval($rub), $unit[1][0],$unit[1][1],$unit[1][2]); // rub
        $out[] = $kop.' '.morph($kop,$unit[0][0],$unit[0][1],$unit[0][2]); // kop
        return trim(preg_replace('/ {2,}/', ' ', join(' ',$out)));
    }

    /**
    * Склоняем словоформу
    */
    public function morph($n, $f1, $f2, $f5) {
        $n = abs(intval($n)) % 100;
        if ($n>10 && $n<20) return $f5;
        $n = $n % 10;
        if ($n>1 && $n<5) return $f2;
        if ($n==1) return $f1;
        return $f5;
    }
 

Пример использования:


        num2str(878867.15); // восемьсот семьдесят восемь тысяч восемьсот шестьдесят семь рублей 15 копеек
     

2. Класс


    class NumToText {
        var $Mant = array(); // описания мантисс
        // к примеру ('рубль', 'рубля', 'рублей')
        // или ('метр', 'метра', 'метров')
        var $Expon = array(); // описания экспонент
        // к примеру ('копейка', 'копейки', 'копеек')

        function Num2Text(){
        }

        // установка описания мантисс
        function SetMant($mant){
            $this->Mant = $mant;
        }
        /**
        * установка описания экспонент
        */
        function SetExpon($expon){
            $this->Expon = $expon;
        }

        /** функция возвращает необходимый индекс описаний разряда
        * ('миллион', 'миллиона', 'миллионов') для числа $ins
        * например для 29 вернется 2 (миллионов)
        * $ins максимум два числа
        * @param $ins integer
        * @return int
        */
        function DescrIdx($ins){
            if(intval($ins/10) == 1) // числа 10 - 19: 10 миллионов, 17 миллионов
                return 2;
            else {
                // для остальных десятков возьмем единицу
                $tmp = $ins%10;
                if($tmp == 1) // 1: 21 миллион, 1 миллион
                    return 0;
                else if($tmp >= 2 && $tmp <= 4)
                    return 1; // 2-4: 62 миллиона
                else
                    return 2; // 5-9 48 миллионов
            }
        }

        // IN: $in - число,
        // $raz - разряд числа - 1, 1000, 1000000 и т.д.
        // внутри функции число $in меняется
        // $ar_descr - массив описаний разряда ('миллион', 'миллиона', 'миллионов') и т.д.
        // $fem - признак женского рода разряда числа (true для тысячи)
        function DescrSot(&$in, $raz, $ar_descr, $fem = false){
            $ret = '';

            $conv = intval($in / $raz);
            $in %= $raz;

            $descr = $ar_descr[ $this->DescrIdx($conv%100) ];

            if($conv >= 100){
                $Sot = array('сто', 'двести', 'триста', 'четыреста', 'пятьсот',
                'шестьсот', 'семьсот', 'восемьсот', 'девятьсот');
                $ret = $Sot[intval($conv/100) - 1] . ' ';
                $conv %= 100;
            }

            if($conv >= 10){
                $i = intval($conv / 10);
                if($i == 1){
                    $DesEd = array('десять', 'одиннадцать', 'двенадцать', 'тринадцать',
                            'четырнадцать', 'пятнадцать', 'шестнадцать', 'семнадцать',
                            'восемнадцать', 'девятнадцать' );
                    $ret .= $DesEd[ $conv - 10 ] . ' ';
                    $ret .= $descr;
                    // возвращаемся здесь
                return $ret;
                }
                $Des = array('двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят',
                'семьдесят', 'восемьдесят', 'девяносто' );
                $ret .= $Des[$i - 2] . ' ';
            }

            $i = $conv % 10;
            if($i > 0){
                if( $fem && ($i==1 || $i==2) ){
                    // для женского рода (сто одна тысяча)
                    $Ed = array('одна', 'две');
                    $ret .= $Ed[$i - 1] . ' ';
                } else {
                    $Ed = array('один', 'два', 'три', 'четыре', 'пять',
                    'шесть', 'семь', 'восемь', 'девять' );
                    $ret .= $Ed[$i - 1] . ' ';
                }
            }
            $ret .= $descr;
            return $ret;
        }

        // IN: $sum - число, например 1256.18
        function Convert($sum){
            $ret = '';

            // имена данных перменных остались от предыдущей версии
            // когда скрипт конвертировал только денежные суммы
            $Kop = 0;
            $Rub = 0;

            $sum = trim($sum);
            // удалим пробелы внутри числа
            $sum = str_replace(' ', '', $sum);

            // флаг отрицательного числа
            $sign = false;
            if($sum[0] == '-'){
                $sum = substr($sum, 1);
                $sign = true;
            }

            // заменим запятую на точку, если она есть
            $sum = str_replace(',', '.', $sum);

            $Rub = intval($sum);
            $Kop = $sum*100 - $Rub*100;

            if($Rub){
                // значение $Rub изменяется внутри функции DescrSot
                // новое значение: $Rub %= 1000000000 для миллиарда
                if($Rub >= 1000000000)
                    $ret .= $this->DescrSot($Rub, 1000000000, array('миллиард', 'миллиарда', 'миллиардов')) . ' ';
                if($Rub >= 1000000)
                    $ret .= $this->DescrSot($Rub, 1000000, array('миллион', 'миллиона', 'миллионов') ) . ' ';
                if($Rub >= 1000)
                    $ret .= $this->DescrSot($Rub, 1000, array('тысяча', 'тысячи', 'тысяч'), true) . ' ';

                $ret .= $this->DescrSot($Rub, 1, $this->Mant) . ' ';

                // если необходимо поднимем регистр первой буквы
                $ret[0] = chr( ord($ret[0]) + ord('A') - ord('a') );
                // для корректно локализованных систем можно закрыть верхнюю строку
                // и раскомментировать следующую (для легкости сопровождения)
                // $ret[0] = strtoupper($ret[0]);
            }
            if($Kop < 10)
                $ret .= '0';

            $ret .= $Kop . ' ' . $this->Expon[ $this->DescrIdx($Kop) ];

            // если число было отрицательным добавим минус
            if($sign)
                $ret = '-' . $ret;

            return $ret;
        }
    }
 

Использование:


    $mt = new NumToText();
    $mt->SetMant( array('рубль', 'рубля', 'рублей') );
    $mt->SetExpon( array('копейка', 'копейки', 'копеек') );
    echo $mt->Convert($HTTP_POST_VARS['num']);
     

Важлива інформація

Міністерство оборони
України
з 24.02 по 11.11
втрати противника
орієнтовно склали:
710660 ( +1770 ) особового складу
9253 ( +4 ) танків
18766 ( +40 ) бойових бронемашин
20314 ( +34 ) артилерійських систем
1245 ( +0 ) РСЗВ
996 ( +0 ) засоби ППО
369 ( +0 ) літаків
329 ( +0 ) гелікоптерів
28802 ( +119 ) автомобільної техніки
28 ( +0 ) кораблі / катери
2636 ( +2 ) крилаті ракети
18676 ( +57 ) БПЛА
3620 ( +16 ) спец. техніки
4 ( +0 ) установок ОТРК/ТРК
1 ( +0 ) підводні човни