webew
Войти » Регистрация
 
PHP

Число прописью средствами PHP

1 мая 2008, 21:35
Автор: Григорий Рубцов [rgbeast]

В статье рассмотрен пример функции на языке PHP, формирующей числительные для использования с существительными мужского и женского рода. Такая функция может пригодиться для автоматического формирования счетов, договоров, актов или сообщений на сайте. На оригинальность или новизну не претендую, очевидно, что аналигичные решения существуют давно.

В русском языке существительное, употребляемое вместе с числительным, имеет три формы. Рассмотрим пример:

Мы видим, что три различных формы существительного отвечают числительным 1,2 и 5. Кроме того, числительные для существительных женского рода другие, см. пример ниже:

Женский род числительных требуется даже для описания существительных мужского рода, так как слово «тысяча» — слово женского рода.

Функция written_number(), приведенная ниже, имеет два аргумента. Первый аргумент — целое неотрицательное число (меньше миллиарда), второй — род (0 - мужской, 1 женский).

<?php
global $N0, $Ne0, $Ne1, $Ne2, $Ne3, $Ne6;

$N0 = 'ноль';

$Ne0 = array(
             0 => array('','один','два','три','четыре','пять','шесть',
                        'семь','восемь','девять','десять','одиннадцать',
                        'двенадцать','тринадцать','четырнадцать','пятнадцать',
                        'шестнадцать','семнадцать','восемнадцать','девятнадцать'),
             1 => array('','одна','две','три','четыре','пять','шесть',
                        'семь','восемь','девять','десять','одиннадцать',
                        'двенадцать','тринадцать','четырнадцать','пятнадцать',
                        'шестнадцать','семнадцать','восемнадцать','девятнадцать')
             );

$Ne1 = array('','десять','двадцать','тридцать','сорок','пятьдесят',
             'шестьдесят','семьдесят','восемьдесят','девяносто');

$Ne2 = array('','сто','двести','триста','четыреста','пятьсот',
             'шестьсот','семьсот','восемьсот','девятьсот');

$Ne3 = array(1 => 'тысяча', 2 => 'тысячи', 5 => 'тысяч');

$Ne6 = array(1 => 'миллион', 2 => 'миллиона', 5 => 'миллионов');

function written_number($i, $female=false) {
  global $N0;
  if ( ($i<0) || ($i>=1e9) || !is_int($i) ) {
    return false; // Аргумент должен быть неотрицательным целым числом, не превышающим 1 миллион
  }
  if($i==0) {
    return $N0;
  }
  else {
    return preg_replace( array('/s+/','/\s$/'),
                         array(' ',''),
                         num1e9($i, $female));
    return num1e9($i, $female);
  }
}

function num_125($n) {
  /* форма склонения слова, существительное с числительным склоняется
   одним из трех способов: 1 миллион, 2 миллиона, 5 миллионов */

  $n100 = $n % 100;
  $n10 = $n % 10;
  if( ($n100 > 10) && ($n100 < 20) ) {
    return 5;
  }
  elseif( $n10 == 1) {
    return 1;
  }
  elseif( ($n10 >= 2) && ($n10 <= 4) ) {
    return 2;
  }
  else {
    return 5;
  }
}

function num1e9($i, $female) {
  global $Ne6;
  if($i<1e6) {
    return num1e6($i, $female);
  }
  else {
    return num1000(intval($i/1e6), false) . ' ' .
      $Ne6[num_125(intval($i/1e6))] . ' ' . num1e6($i%1e6, $female);
  }
}

function num1e6($i, $female) {
  global $Ne3;
  if($i<1000) {
    return num1000($i, $female);
  }
  else {
    return num1000(intval($i/1000), true) . ' ' .
      $Ne3[num_125(intval($i/1000))] . ' ' . num1000($i%1000, $female);
  }
}

function num1000($i, $female) {
  global $Ne2;
  if( $i<100) {
    return num100($i, $female);
  }
  else {
    return $Ne2[intval($i/100)] . (($i%100)?(' '. num100($i%100, $female)):'');
  }
}

function num100($i, $female) {
  global $Ne0, $Ne1;
  $gender = $female?1:0;
  if ($i<20) {
    return $Ne0[$gender][$i];
  }
  else {
    return $Ne1[intval($i/10)] . (($i%10)?(' ' . $Ne0[$gender][$i%10]):'');
  }
}

?>

Рассмотрим примеры использования функции written_number():

$ruble = array(1 => 'рубль', 2 => 'рубля', 5 => 'рублей');
$sum = 21802;
echo 'Всего оказано услуг на сумму: '
    .  written_number($sum) . ' ' . $ruble[num_125($sum)] . ' 00 коп.';
$friendm = array(1 => 'друг', 2 => 'друга', 5 => 'друзей');
$friendf = array(1 => 'подруга', 2 => 'подруги', 5 => 'подруг');
$m_count = 11;
$f_count = 21;
echo 'У пользователя ' . written_number($m_count) . ' ' . $friendm[num_125($m_count)]
    . ' и ' . written_number($f_count, true) . ' ' . $friendf[num_125($f_count)] . '.';

Статья написана по материалам онлайн-курса «Программирование на PHP».


© Все права на данную статью принадлежат порталу webew.ru. Перепечатка в интернет-изданиях разрешается только с указанием автора и прямой ссылки на оригинальную статью. Перепечатка в печатных изданиях допускается только с разрешения редакции.
Добавить комментарий
Отображение комментариев: Древовидное | Плоское

bur

Наверное, ошибка:

$friendm = array(1 => 'друг', 2 => 'друга', 5 => 'друзей');
$friendf = array(1 => 'подруга', 2 => 'подруги', 5 => 'подруг');
$m_count = 11;
$f_count = 1000;
echo 'У пользователя ' . written_number($m_count) . ' ' . $friendm[num_125($m_count)]
    . ' и ' . written_number($f_count, true) . ' ' . $friendf[num_125($f_count)] . '.' . '<br>';



Выведет:
У пользователя одиннадцать друзей и одна тысяча ноль подруг
Fastcoder.org — портал для JavaScrpt-программистов
05.05.2008, 00:51
Ответить
NO USERPIC

rgbeast

Спасибо за багу, исправил.
05.05.2008, 01:04
Ответить

bur

А не лучше ли, в случае неверного типа входных данных, вместо die возвращать переданный аргумент? Мало ли, вдруг там число больше миллиона. Тогда правильней вернуть его, а не обрушивать весь скрипт. Ведь die довольно мощная функция. Она не только репортит ошибку, но и прекращает дальнейшую интерпритацию всего скрипта.
Fastcoder.org — портал для JavaScrpt-программистов
05.05.2008, 02:08
Ответить
NO USERPIC

rgbeast

die() в функции written_number() стояла скорее как маркер, чем как функциональная возможность, заменил die() на return false. Скрипт, вызывающий функцию, должен теперь сам обработать ошибку. Конкретная реализация обработки ошибки будет зависеть от логики приложения.
05.05.2008, 02:51
Ответить
NO USERPIC

remitmaster

В избранное... спасибо!
22.06.2008, 16:15
Ответить
NO USERPIC

doron

Огромное спс
02.01.2009, 13:33
Ответить
NO USERPIC

altsoph

В свое время решал эту задачу в более широком варианте.

Основные плюсы моего решения:
* реализация в виде отдельной библиотеки
* поддержка 6 русских падежей
* набор готовых перечислимых объектов (штуки, рубли, копейки, центы и т. п.) + возможность передать библиотеке произвольный перечислимый объект
* обработка и склонение десятичных дробей (до 6 знаков после запятой)

Более подробное описание, возможность поиграть с примерами и скачать код тут:
http://altsoph.ru/?p=522
24.02.2009, 13:43
Ответить
Добавить комментарий
Отображение комментариев: Древовидное | Плоское
© 2007—2010 webew.ru, связаться: x собака webew.ru
Сайт использует Flede и соответствует стандартам WAI-WCAG 1.0 на уровне A.
Rambler's Top100