1 (edited by PunBB 2017.02.03 08:23)

Topic: Склонение существительных после числительных в PHP

Существительное после числительного в зависимости от последнего может иметь три формы: "1 рубль", "3 рубля", "5 рублей". Следующая PHP-функция реализует склонение:

function format_by_count($count, $form1, $form2, $form3)
{
    $count = abs($count) % 100;
    $lcount = $count % 10;
    if ($count >= 11 && $count <= 19) return($form3);
    if ($lcount >= 2 && $lcount <= 4) return($form2);
    if ($lcount == 1) return($form1);
    return $form3;
}

Используем функцию следующим образом:

$count = 7;
echo $count . ' ' . format_by_count($count, 'день', 'дня', 'дней');

Как видим, все работает, но актуально только для рашн пипл...

2 (edited by PunBB 2017.02.03 08:21)

Re: Склонение существительных после числительных в PHP

В интернете можно встретить много функций для склонения существительных после числительного остатка. Вот некоторые примеры, которые я нашел:

Еще одна функция на языке PHP, которую можно использовать для вывода корректного окончания в существительных после числительного. Например: «3 места», «17 пользователей» и т.д.

function smart_ending($number, $forms, $base = '') 
{
  $rest = $number % 10;
  $number = (int) substr($number, -2, 2);
  if ($rest == 1 && $number != 11) return $base.$forms[0];
  elseif (in_array($rest, array(2, 3, 4)) && !in_array($number, array(12, 13, 14))) return $base.$forms[1];
  else return $base.$forms[2];
}

Функция принимает на вход от 2 до 3 параметров. Первый параметр ($number) — это число, собственно, само числительное. Второй параметр ($forms) это массив форм существительного. Третий параметр ($base) — неизменяющаяся основа слова, его можно указывать для сокращения записи, если в этом есть необходимость.

Например, результат работы функции в обоих случаях будет идентичен:

echo smart_ending(17, array('пользователь', 'пользователя', 'пользователей')); //пользователей
echo smart_ending(17, array('ь', 'я', 'ей'), 'пользовател'); //пользователей

Также иногда может быть, что при склонении существительное полностью меняет свою форму. В таких случаях возможен только один вариант вызова функции — без параметра $base.

echo smart_ending(21, array('день', 'дня', 'дней')); //день

Как это работает?

Существует три варианта склонения:

Если остаток от деления числительного на 10 равен 1.
Например это числа: 1, 21, 31 и т.д. Форма существительного для них будет одинакова: «1 день», «21 билет».

Но, исключение составляет число 11 и заканчивающиеся на 11 числа 111, 211 и т.д. Остаток от деления таких чисел на 10 тоже равен 1, но использовать ту же форму существительного нельзя: «11 день».

Поэтому в функции этот момент должен учитываться.

Если остаток от деления числительного на 10 равен 2, 3 или 4.
Например это числа: 2, 23, 34 и т.д. Форма существительного для них будет тоже одинакова: «22 дня», «4 билета».

Но, опять не обошлось без исключений. Числа 12, 13, 14 и заканчивающиеся на эти цифры числа 114, 212 и т.д. Как и в предыдущем случае, остаток от деления таких чисел на 10 удовлетворяет условию, но форма существительного будет неверна: «14 дня».

Этот момент тоже должен учитываться в функции.

Все остальные остатки от деления числительного на 10, а также исключения из предыдущих двух вариантов — используют третью форму существительного. Примеры: «12 дней», «18 билетов», «111 часов».

Все эти условия отражены в функции smart_ending, обеспечивая тем самым корректность её работы. НО... попробуйте ей просклонять слова - Человек или Людей...

3 (edited by PunBB 2017.02.03 10:21)

Re: Склонение существительных после числительных в PHP

Вот написал функцию для PunBB, чтобы можно было использовать на разных языках, добавил ее в свой фреймворк.

Сам принцип склонения существительных следующий:

//Author PunBB
//Created 03/02/2017

//подготавливаем массив, к примеру на русском
$lang_pan_statistic = array (
   'views_one'         => 'просмотр',
   'views_several'         => 'просмотра',
   'views_many'         => 'просмотров',

   'users_one'         => 'посетитель',
   'users_several'         => 'посетителя',
   'users_many'         => 'посетителей',
);


function pan_fw_nouns_after_num($count, $form1='', $form2='', $form3='')
{
   global $forum_user;
   
   $binary = abs($count) % 100;
   $single = $count % 10;
   
   if ($forum_user['language'] == 'Russian')
   {
      if ($binary >= 11 && $binary <= 19) 
         return($form3);
      if ($single >= 2 && $single <= 4)
         return($form2);
      if ($single == 1)
         return($form1);
      
      ($hook = get_hook('pan_fw_fn_nouns_after_num_new_lang')) ? eval($hook) : null;
      
   } else {
      if ($count == 1)
         return($form1);
      else
         return($form2);
   }
   
   return $form3;
}

Использовать очень просто:

$num_users = 2411;

echo $num_users .' - ' . pan_fw_nouns_after_num($num_users , $lang_pan_statistic['users_one'], $lang_pan_statistic['users_several'], $lang_pan_statistic['users_many']);

//2411 - посетителей

На английском массив существительных будет проще:

//Array on English
$lang_pan_statistic = array (
   'views_one'         => 'view',
   'views_several'         => 'views',
   'views_many'         => 'views',

   'users_one'         => 'user',
   'users_several'         => 'users',
   'users_many'         => 'users',
);

Конечно. можно упростить еще функцию, если использовать цикл for, но это уже дело мастера  PunBB_INFO_ICQ/smile