Склонение существительных после количества, или 101 товар / 2 товара / 8 товаров

Часто при создании интернет магазинов и в других местах, где нужно показать количество во множественном числе - нужно пойти на некоторые хитрости. Первое решение, самое простое, вывести слово перед числом и указать некую общую форму, например, Товаров в корзине: 3, или в скобках прописать 3 товара(ов), но мы то хотим сделать всё красиво, поэтому, разберемся в сути вопроса. Нам нужно понять как подставлять правильное окончание слов в зависимости от количества.

Статья несет больше образовательный характер, чтобы получить готовый алгоритм и не вдаваться в подробности - можете пролистать до конца. Если загуглить склонение существительных после поличества, то можно найти много готовых примеров кода на разных языках программирования - JavaScript, C, PHP, но если вникнуть в суть самого алгоритма, то вы его сможете написать на любом языке, хоть на паскале, поэтому, решил разобраться в этой теме...

Для начала попробуем просклонять несколько слов - Товар, Ящик, Зубочистка, Конфета

Количество\Слово Товар Ящик Зубочистка Конфета
0 Товаров Ящиков Зубочисток Конфет
1 Товар Ящик Зубочистка Конфета
2 Товара Ящика Зубочистки Конфеты
3 Товара Ящика Зубочистки Конфеты
4 Товара Ящика Зубочистки Конфеты
5 Товаров Ящиков Зубочисток Конфет
6 Товаров Ящиков Зубочисток Конфет
7 Товаров Ящиков Зубочисток Конфет
8 Товаров Ящиков Зубочисток Конфет
9 Товаров Ящиков Зубочисток Конфет
10 Товаров Ящиков Зубочисток Конфет

Попробуем упростить эту таблицу

Количество\Слово Товар Ящик Зубочистка Конфета
0, 5-10 Товаров Ящиков Зубочисток Конфет
1 Товар Ящик Зубочистка Конфета
2-4 Товара Ящика Зубочистки Конфеты

Т.е. мы имеем всего три формы слова, если в пределах от 0 до 9

  1. Для одного - именительный падеж (кто/что)
  2. От 2х до 4х - родительный падеж (кого/чего)
  3. От 5 до 9 и 0 - множественное число (много конфет, много ящиков, много товаров...)
но количество 0 нужно обратывать правильно, писать пусто или нет в корзине ничего или конфет сегодня не будет...

Продолжим наше исследование на диапазоне от 11 до 30, теперь уже по одному слову...

Число Форма
11 Товаров
12 Товаров
13 Товаров
14 Товаров
15 Товаров
16 Товаров
17 Товаров
18 Товаров
19 Товаров
20 Товаров
21 Товар
22 Товара
23 Товара
24 Товара
25 Товаров
26 Товаров
27 Товаров
28 Товаров
29 Товаров
30 Товаров

С 11 до 19 ситуация не меняется, но вот если сравнить таблицу первую с 0 до 10 с таблицей от 20 до 30, то ситуация в точности повторяется, очень интересно!

А что за числа с 11 до 19, это числа с окончанием "надцать" (одинадцать, пятнадцать, девятнадцать).

Теперь можете перепроверить, но я уже проверил сам, с 0 до 100 ситуация повторяет в точности ситуацию с 0 до 10,  исключением из этого будет только  то, что заканчивается на "надцать". Я бы даже сказал что от 0 до 9, во всех числах берется последняя цифра и по ней решается какая форма слова будет.

А что дальше? Дальше подставляйте хоть 1000, хоть миллион, ситуация повторится, решающими будут две последние цифры, если число заканчивается на 11-19 и во всех остальных случаях одна последняя цифра.

Какой алгоритм получится в результате?

  1. Отсекаем две последние цифры от числа, проверяем не находится ли это в диапазоне от 11 до 19, если так, то отдаем множественное число (п3).
  2. Отсекаем еще раз от этого одну последнюю цифру - если 1, то отдаем именительный падеж (п1)
  3. Если это цифра от 2 до 4, то отдаем родительный падеж.
  4. Во всех остальных случаях множественное число.

В некоторых алгоритмах просят вводить три формы слова, где-то 1,3,5, а где-то 1,2,4 или 1,2,7, но это сути не меняет, мы будем входными параметрами в функции использовать количество 1 (яблоко),2 (яблока),5 (яблок).

Пример на моем любимом PHP

$n - количество

$f1 = яблоко

$f2 = яблока

$f5 = яблок

public static function num_morph($n, $f1, $f2, $f5) 
	{
	    $n = (abs($n) % 100); //отсекаем две последние цифры от цисла
	    
		//если это от 11 до 19, вернем множ. число
	    if ($n>=11 && $n<=19) return $f5; 

	    $n1= $n % 10; //отсекаем от этого последнюю цифру

        //единственное число                     
	    if ($n1==1) return $f1;
		
        //родительный падеж
	    if ($n1>1 && $n1<5) return $f2;
        
        //во всех остальных случаях множественное число
	    return $f5;
	}

Если остались вопросы - задавайте в комментариях...

Показать комментарии