Guest User

Untitled

a guest
Dec 13th, 2018
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.90 KB | None | 0 0
  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. }
Add Comment
Please, Sign In to add comment