SHARE
TWEET

Untitled

a guest Dec 13th, 2018 58 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2.  
  3. namespace App\Services;
  4.  
  5.  
  6. class NumberService
  7. {
  8.  
  9.     public static function priceToText(string $price)
  10.     {
  11.         preg_replace("/(\\.|,)+/", '.', strval($price));
  12.  
  13.         // Делим на рубли и копейки
  14.         $segments = explode(".", strval($price));
  15.  
  16.         $rub = self::numberToText($segments[0]) . ' '
  17.                . self::declOfNumber($segments[0], ['рубль', 'рубля', 'рублей']);
  18.  
  19.         // Если есть копейки
  20.         if (count($segments) > 1) {
  21.             if (strlen($segments[1]) === 1) {
  22.                 $segments[1] .= '0';
  23.             }
  24.  
  25.             $kop = self::numberToText($segments[1], true) . ' '
  26.                    . self::declOfNumber($segments[1],
  27.                     ['копейка', 'копейки', 'копеек']);
  28.  
  29.             return "$rub, $kop";
  30.         }
  31.  
  32.         return $rub;
  33.     }
  34.  
  35.  
  36.     public static function numberToText(string $num, $feminine = false)
  37.     {
  38.         // Разряды
  39.         $numbers = [
  40.             0 => [
  41.                 '0' => 'ноль',
  42.                 '1' => ['один', 'одна'],
  43.                 '2' => ['два', 'две'],
  44.                 '3' => 'три',
  45.                 '4' => 'четыре',
  46.                 '5' => 'пять',
  47.                 '6' => 'шесть',
  48.                 '7' => 'семь',
  49.                 '8' => 'восемь',
  50.                 '9' => 'девять',
  51.             ],
  52.             1 => [
  53.                 '1' => 'десять',
  54.                 '2' => 'двадцать',
  55.                 '3' => 'тридцать',
  56.                 '4' => 'сорок',
  57.                 '5' => 'пятьдесят',
  58.                 '6' => 'шестьдесят',
  59.                 '7' => 'семьдесят',
  60.                 '8' => 'восемьдесят',
  61.                 '9' => 'девяносто',
  62.             ],
  63.             2 => [
  64.                 '1' => 'сто',
  65.                 '2' => 'двести',
  66.                 '3' => 'триста',
  67.                 '4' => 'четыреста',
  68.                 '5' => 'пятьсот',
  69.                 '6' => 'шестьсот',
  70.                 '7' => 'семьсот',
  71.                 '8' => 'восемьсот',
  72.                 '9' => 'девятьсот',
  73.             ],
  74.         ];
  75.  
  76.         // Спецчисла
  77.         $teens = [
  78.             '1' => 'одиннадцать',
  79.             '2' => 'двенадцать',
  80.             '3' => 'тринадцать',
  81.             '4' => 'четырнадцать',
  82.             '5' => 'пятнадцать',
  83.             '6' => 'шестнадцать',
  84.             '7' => 'семнадцать',
  85.             '8' => 'восемнадцать',
  86.             '9' => 'девятнадцать',
  87.         ];
  88.  
  89.         // Системы чисел
  90.         $numberSystems = [
  91.             1 => ['тысяча', 'тысячи', 'тысяч'],
  92.             2 => ['миллион', 'миллиона', 'миллионов'],
  93.             3 => ['миллиард', 'миллиарда', 'миллиардов'],
  94.         ];
  95.  
  96.         // Делим число на сегменты по три знака с конца
  97.         $numItems = preg_split("/(?=(?:\d{3})+(?!\d))/", strval($num));
  98.  
  99.         $resultArray = [];
  100.  
  101.         // Перебираем сегменты с конца
  102.         foreach (array_reverse($numItems) as $itemId => $item) {
  103.             $result = '';
  104.  
  105.             // Делим сегмент на цифры и переворачиваем
  106.             $itemArray = array_reverse(preg_split('//u', $item,
  107.                 null, PREG_SPLIT_NO_EMPTY));
  108.  
  109.             // Перебираем цифры
  110.             foreach ($itemArray as $elId => $el) {
  111.                 // Если первая цифра тысяч равна 1, но тысячи не заканчиваются на 11,
  112.                 // , то добавляем в результат число женского рода и пропускаем итерацию
  113.                 if ($itemId === 1 && $elId === 0
  114.                     && (($item % 10 === 1 && $item % 100 !== 11)
  115.                         || ($el === '2' && $item % 100 !== 12))
  116.                 ) {
  117.                     $result = $numbers[$elId][$el][1] . ' ' . $result;
  118.  
  119.                     continue;
  120.                 }
  121.  
  122.                 // Если цифр в сегменте больше одной
  123.                 if (count($itemArray) > 1) {
  124.                     // Если находимся на первой цифре и вторая цифра равна 1
  125.                     // , или если текущая цифра равна 0, то пропускаем итерацию
  126.                     if (($elId === 0 && $itemArray[1] === '1') || $el === '0') {
  127.                         continue;
  128.                     }
  129.  
  130.                     // Иначе если находимся на второй цифре и она равна 1
  131.                     // , и первая цифра не равна 0, то добавляем спецчисло в результат
  132.                     // и пропускаем итерацию
  133.                     elseif ($elId === 1 && $itemArray[0] !== '0'
  134.                             && $el === '1'
  135.                     ) {
  136.                         $result = $teens[$itemArray[0]] . ' ' . $result;
  137.  
  138.                         continue;
  139.                     }
  140.                 }
  141.  
  142.                 // Если первая цифра равна 1 или 2, то добавляем в результат
  143.                 // число выбранного рода и пропускаем итерацию
  144.                 if ($elId === 0 && ($el === '1' || $el === '2')) {
  145.                     $result = $numbers[$elId][$el][$feminine ? 1 : 0]
  146.                               . ' ' . $result;
  147.  
  148.                     continue;
  149.                 }
  150.  
  151.                 // Добавляем цифру исходя из разряда
  152.                 $result = $numbers[$elId][$el] . ' ' . $result;
  153.             }
  154.  
  155.             // Если результат не пустой
  156.             if ($result = trim($result, ' .,\t\n\r')) {
  157.                 // Если сегмент не первый, то добавляем систему чисел в результат
  158.                 if ($itemId) {
  159.                     $system = self::declOfNumber($item,
  160.                         $numberSystems[$itemId]);
  161.  
  162.                     $result = $result . ' ' . $system;
  163.                 }
  164.  
  165.                 // Добавляем результат сегмента в массив
  166.                 array_unshift($resultArray, $result);
  167.             }
  168.         }
  169.  
  170.         // Выводим массив результатов через разделитель
  171.         return implode(' ', $resultArray);
  172.     }
  173.  
  174.     // Склонение числительных
  175.     public static function declOfNumber(int $n, array $titles)
  176.     {
  177.         $cases = [2, 0, 1, 1, 1, 2];
  178.  
  179.         return $titles[($n % 100 > 4 && $n % 100 < 20)
  180.             ? 2
  181.             : $cases[($n % 10 < 5) ? $n % 10 : 5]];
  182.     }
  183. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top