Pull to refresh

Comments 122

У себя в проектах использую этот код, не знаю автора, к сожалению, но работает отлично.

/**
 * Возвращает единицу измерения с правильным окончанием
 * 
 * @param {Number} num      Число
 * @param {Object} cases    Варианты слова {nom: 'час', gen: 'часа', plu: 'часов'}
 * @return {String}            
 */
function units(num, cases) {
    num = Math.abs(num);
    
    var word = '';
    
    if (num.toString().indexOf('.') > -1) {
        word = cases.gen;
    } else { 
        word = (
            num % 10 == 1 && num % 100 != 11 
                ? cases.nom
                : num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) 
                    ? cases.gen
                    : cases.plu
        );
    }
    
    return word;
}
проще можно:
/// /// по числу возврщает индекс из массива, чтоб было правильное окончание
/// массив должен быть такой ['просмотр', 'просмотра', 'просмотров']
///
///
///
public static int WorksEnd(int number)
{
if(Regex.Match(number.ToString(), «1\\d$»).Success)
return 2;
if(Regex.Match(number.ToString(), «1$»).Success)
return 0;
if(Regex.Match(number.ToString(), "(2|3|4)$").Success)
return 1;
return 2;
}
На всякий случай, может кому пригодится:
nom — Nominativ, именительный падеж;
gen — Genetiv, родительный падеж;
plu — Plural, множественное число.

UFO landed and left these words here
А вот хотелось бы, чтобы не забивать базы всякими яблоками, одну функцию на все слова, которая определив склонение, сама высчитывала нужное окончание… Даже несмотря на великость и могучесть великого и могучего точность такой функции, на первый взгляд, можно довести до 70%
Для английского писал, причем поддерживала даже user's — users'.
Для русского из-за того, что окончание зависит от рода существительного (пользователь, канитель), не стал писать что-то серьезное.
и ещё от одушевлённости, между прочим, тоже, так что нифига :)
Нет, от одушевленности зависит только окончания при склонении. Видеть кого? Пользователя. Видеть что? Бордель.
Но 5 пользователей, 5 борделей.
Может, я о чем-то забыл, но вроде как на окончание во множественном числе одушевленность не влияет.
Главное не забывать о пользователях, и борделях!
Поправьте меня, если я ошибаюсь, но там кажется задействованы словари, а хотелось как раз без этого
Конечно, словари. Как иначе «человек-люди» во множественное число поставишь. А для слов, которых нет в словаре, прекрасно работает предсказатель, который склоняет слова по аналогии. Что imho работает лучше и проще каких-то вручную прописанных правил.

Прописывание правил в коде в пределе как раз и приводит к составлению словаря (только в довольно корявом и неудобным для поддержки виде).
Сейчас на сайте 10 человеков. Только что зашедшие человеки: Филипп, Туранга.
Тогда уж, продолжая тему:
*Бендер заходит в чат
*Человеки покидает чат
Сейчас на сайте 10 людей. Только что зашедшие люди: Филипп, Туранга.

один фиг
сейчас на сайте 1 людь

(извините, что отвечаю в старую тему)
(извините, что отвечаю в старую тему)

Да ничего страшного.
Так ведь все еще актуально =)
Есть и PHPMorphy, но там словари по 7 Мб и ресурсов он кушает прилично. А в большинстве задач заранее известно чего будет спрягаться. Так что не вижу особой выгоды в универсальной функции.
угу, морфология для этого — из пушки по воробьям. Разве что слова из базы обрабатывать.

введите название предмета: сепулька
у Вас 15 сепулек
— Дайте мне пять шаурмей, ммм… 5 шаурменей, 5 шаурмов…
— Дайте мне две шаурмы и три шаурмы.
Весьма рекомендую использовать тщательно собранные формулы для разных языков translate.sourceforge.net/wiki/l10n/pluralforms

PHP-шники аккуратно, там формулы даны для С, а в С немного другие приоритеты операторов, потому придётся расставить скобочки.
Для тех, кто использует Smarty:
<?php
function smarty_function_ending($params, &$smarty)
{
$base = !isset($params['base']) ? '' : $params['base'];

$e0 = $params['e0'];
$e1 = $params['e1'];
$e2 = $params['e2'];
$number = $params['number'];

if ($number % 100 > 10 && $number % 100 < 20) return $base . $e0;
if ($number % 10 == 1) return $base . $e1;
if ($number % 10 >= 2 && $number % 10 <= 4) return $base . $e2;
return $base . $e0;
}


ложим в smarty/plugins/function.ending.php и используем
{$item.comments} {ending number=$item.comments base=«комментар» e0='иев' e1='ий' e2='ия'}
Отлично, теперь мы будем ложить со склонениями!
Я с вас фигею, ребят. Человек дает вам работающее программное решение и получает минусы. Ему отвечают банальным занудством и огребают кучу плюсов. Ну-ну… а мы-то и не знали, как правильно: лОжить или ложИть.
Ну-ну… Раз вы не знали, то правильно: класть.
как ты заверстаешь такие фразы?
* к комментарию не добавлено плюсов
* к комментарию добавлен плюс
* к комментарию добавлены 2 плюса
* к комментарию добавлены 5 плюсов

попутно… как правильно?
* к комментарию добавлен 1.1 плюс
* к комментарию добавлен 1.1 плюса
Где то так:
к комментарию
{if $comments == 0}
не добавлено плюсов
{elseif $comments == 1}
добавлен плюс
{else}
добавлены {$comments} {ending number=$comments base="плюс" e0="ов" e1="" e2="а"}
{/if}


попутно — думаю что правильнее «к комментарию добавлен 1.1 плюса» — «одна целая одна десятая плюса», но приведенный мной код не работает правильно с дробными числами.
вот видишь, пришлось добавлять пачку исключений… а ведь куда приятней было бы так:

к комментарию {count $comments}не добавлено{/}добавлен{/}добавлены {$comments}{/count} {plural $comments}плюсов{/}плюс{/}плюса{/plural}

«одна целая одна десятая плюса» — так не говорят, говорят: «один и один плюс»
уууу извращенец!
громоздковатая конструкция, не находишь?
для тех, кто использует смарти имхо проще сделать как то так:

<?php
function smarty_modifier_russify($i, $s1, $s4 = false, $s5 = false)
{
    if (false == $s4) $s4 = $s1;
    if (false == $s5) $s5 = $s1;
    return Funcs::getRussianNumEnding($i, array($s1, $s4, $s5));
}
?>

суём это дело в \smarty\plugins\modifier.russify.php и используем:

{$item.comments} комментар{$item.comments|russify:'иев':'ий':'ия'}

ну или там

Всего пользователей: {$usersTotal} {$usersTotal|russify:'человек':'человека'}
>массив слов (или окончаний для слов) для чисел 1, 4 и 5

проще запомнить как «один», «два», «много»
Вообще в такие функции обычно передаются окончания для чисел 0, 1 и 2 (согласитесь, это намного логичнее чем 1,4 и 5 или любой другой вариант).

И, надо сказать, я удивлен таким постом, рассказывающем абсолютно банальные вещи — не надо пожалуйста опускать планку статей ниже плинтуса. А то такими темпами скоро появятся статью «Условные операторы в PHP» или «Как включить компьютер»
Полезной информации в виде реализации в данном топике тоже не вижу — если уж программист не способен 1 раз в жизни написать для себя функцию в 10 строк, то гугл в помощь — на первых строках в выдаче есть реализации получше предложенной.
Можно было не приводить примеры функций, они и в самом деле элементарны. Тут скорее попытка привлечь внимание общественности к проблеме. Но выложить на Хабре статью и без примера — это как-то, по-моему, странно.
Я понял. Но в итоге просто у вас получилась статья на 2 экрана, вся суть которой умещается в 1 предложение.
Угу. Лучше бы раскрыли тему интеграции с gettext, в котором эти функции уже зашиты для кучи языков.
Пользователь elfiki когда-то написал лаконичную функцию на PHP, пост с которой почему-то быстро поместил в черновики. К счастью, я успел зазвездить пост в ридере.

/**
* @param $number int число чего-либо
* @param $titles array варинаты написания для количества 1, 2 и 5
* @return string
*/
function human_plural_form($number, $titles=array('комментарий','комментария','комментариев')){
$cases = array (2, 0, 1, 1, 1, 2);
return $number." ".$titles[ ($number%100>4 && $number%100<20)? 2: $cases[min($number%10, 5)] ];
}
Мои вариант. Вроде как короче выглядит.

//Для вывода статистики на екран.
//firststr — пользователь
//secondstr — пользователя
//thirdstr — пользователей
function get_name($count,$firststr,$secondstr,$thirdstr)
{
$ost = $count % 100;
if ($ost > 9 && $ost < 20)
{
return $thirdstr;
}
else
{
$ost = $ost % 10;
if ($ost == 1)
return $firststr;
elseif ($ost > 1 && $ost < 5)
return $secondstr;
else
return $thirdstr;
}
}
Рад что перешел на Ruby on Rails и использую, сейчас уже встроенную, библиотеку i18n
gettext тоже умеет plurals
$plural = $n%10==1&&$n%100!=11?'комментарий':($n%10>=2&&$n%10<=4&&($n%100<10||$n%100>=20)?'комментария':'комментариев');

я думал, алгоритм подстановки слова в нужной форме уже ни для кого не секрет :-)
Топик медленно перетекает в «Самые извращенские реализации функции окончания числительных» :)
Это называется склонение существительных после числительных, а не «спряжение слов по числам».
а перед числительными их типа склонять не надо?
сорри, вот:
    function declOfNum($number, $titles)  
    {  
        $cases = array (2, 0, 1, 1, 1, 2);  
        return $number." ".$titles[ ($number%100 > 4 && $number %100 < 20) ? 2 : $cases[min($number%10, 5)] ];  
    } 
переписывается на JS за 1 минуту, не менее просто :)
в этом коде нет ни одного выражения php, которое отсутствует в Javascript :)

зы: не могу утверждать, но мне кажется, что автор этого кода мой друг (не уверен, потому что он мог его где-то вычитать) — forum.woweb.ru/topic28561.html
UFO landed and left these words here
Не будет бесполезным добавить функции 3ий параметр, отвечающий за обработку нулевого значения, ср.
В теме 0 комментариев
До события осталось нет часов

З.Ы. Это не просьба о помощи, а «хозяйке на заметку»
А можно так:
Сообщения: 12
Устрицы: 76
и т.д. Ведь сайт это все-таки не человек а интерфейс, а в интерфейсах такое вполне допустимо.
Rails (gem russian):

Russian::pluralize
Russian::p

Russian.p(1, "вещь", "вещи", "вещей")
=> "вещь"
Russian.p(2, "вещь", "вещи", "вещей")
=> "вещи"
Russian.p(10, "вещь", "вещи", "вещей")
=> "вещей"
Russian.p(3.14, "вещь", "вещи", "вещей", "вещи") # последний вариант используется для дробных величин
=> "вещи"
кстати, частенько стоящее перед числительным слово тоже меняется.

например:

остался 1 час
осталось 2 часа

так что для полноценной работы функцию стоит дописать.

свою я выкладывать не буду, она страшная и уродливая.
а как там реализован универсальный (для любых языков) способ склонения?
Извините, но запятой после слова «как» не было, так что вопрос был в нём.
Для XML/XSL.
Функция склонения
<!-- Склонение после числительных -->
<xsl:template name="declension">
	<!-- Число -->
	<xsl:param name="number" select="number"/>
	
	<!-- "Комментарий" -->
	<xsl:param name="f0" select="f0" />

	<!-- "Комментария" -->
	<xsl:param name="f1" select="f1" />

	<!-- "Комментариев" -->
	<xsl:param name="f2" select="f2" />
	<xsl:variable name="absnum">
		<xsl:choose>
			<xsl:when test="$number < 0"><xsl:value-of select="0 - $number" /></xsl:when>
			<xsl:otherwise><xsl:value-of select="$number" /></xsl:otherwise>
		</xsl:choose>
	</xsl:variable>
	
	<xsl:choose>
	   <xsl:when test="($absnum mod 10) = 1 and ($absnum mod 100) != 11">
		  <xsl:value-of select="$f0"/>
	   </xsl:when>
	   <xsl:when test="(($absnum mod 10) >= 2) and (($absnum mod 10) <= 4) and (($absnum mod 100 < 10) or ($absnum mod 100 >= 20))">
		  <xsl:value-of select="$f1"/>
	   </xsl:when>
	   <xsl:otherwise>
		  <xsl:value-of select="$f2"/>
	   </xsl:otherwise>
	</xsl:choose>
</xsl:template>

Вызов
<xsl:call-template name="declension">
	<xsl:with-param name="number" select="value-of-your-counter-or-number" />
	
	<xsl:with-param name="f0" select="'комментарий'" />
	<xsl:with-param name="f1" select="'комментария'" />
	<xsl:with-param name="f2" select="'комментариев'" />
</xsl:call-template>

Можно легко усовершенствовать — я подгружал функцией document() XML-словарь по коду языка (en.xml, ru.xml и т.д.), взятому из преобразуемого XML-файла (скажем в root-элементе тег lang с нужным значением) и модифицировал функцию declension для работы с разными языками, передавая не непосредственно слова в 3-х формах, а id фразы/слова из словаря.
Хабрапарсер преобразовал символы… внутри всех параметров test вместо < и > должны быть &gt; и &lt;, т.е. <= и >= надо писать как как &gt;= и &lt;= соответственно.
мы используем похожий шаблон, только с 2 параметрами — первым передаем число, а вторым формы слова через запятую — мне кажется так удобнее чем делать 4 параметра :)
Обалдеть) Буквально 15 минут назад на работе написал такое на C# для количества дней))) Жестоко совпало)

private static string GetDaysWithCase(int daysCount)
{
if (daysCount < 0)
throw new ArgumentException("daysCount");

string days = daysCount.ToString();
string daysCase = "дней";
char lastChar = days[days.Length - 1];

if (days.Length >= 2 && days[days.Length - 2] == '1')
{
// 10-19 дней
}
else if (lastChar == '1')
{
// 1, 21, 31 день
daysCase = "день";
}
else if (lastChar == '2' || lastChar == '3' || lastChar == '4')
{
// 2, 3, 4, 22, 33, 44 дня
daysCase = "дня";
}

return string.Format("{0} {1}", days, daysCase);
}
а подсветка-то и не работает :(
private static string GetDaysWithCase(int daysCount)
    {
      if (daysCount < 0)
        throw new ArgumentException("daysCount");

      string days = daysCount.ToString();
      string daysCase = "дней";
      char lastChar = days[days.Length - 1];

      if (days.Length >= 2 && days[days.Length - 2] == '1')
      {
        // 10-19 дней
      }
      else if (lastChar == '1')
      {
        // 1, 21, 31 день
        daysCase = "день";
      }
      else if (lastChar == '2' || lastChar == '3' || lastChar == '4')
      {
        // 2, 3, 4, 22, 33, 44 дня
        daysCase = "дня";
      }
      
      return string.Format("{0} {1}", days, daysCase);
    }


* This source code was highlighted with Source Code Highlighter.
function declOfNum( $number, $titles ) {
$cases = array( 2, 0, 1, 1, 1, 2 );
return $titles[ ( $number % 100 > 4 && $number % 100 < 20 ) ? 2 : $cases[ mi
n( $number % 10, 5 ) ] ];
}

И не в первый раз.
Не забудьте отдельно обработать случай, для числа 0. Просто написать, например, «0 записей» не достаточно. Нужно как минимум написать «Записей нет» или изменить дизайн, скрыв вообще пустой блок с записями.


Вот удивляет меня эта тяга к максимальному очеловечиванию интерфейса в ущерб удобству. Когда я ищу взглядом на странице количество записей (комментариев, еще чего-нибудь), я ищу число. Числа выделяются посреди текста, по ним можно ориентироваться. Заменяя число текстом, меня лишают этой возможности. Даже когда я привыкну к интерфейсу и буду знать, в каком именно месте отображается количество записей, я всё равно буду спотыкаться взглядом об это «Записей нет», ожидая увидеть цифру на месте количества.

Скрывать пустой блок с записями — тоже не самое разумное решение. Есть возможность, что я буду долго блуждать по странице, пытаясь понять «где же, блин, тут записи должны отображаться». А когда запись появится, меня неприятно удивит блок, внезапно вылезший неизвестно откуда и нарушивший картину, к которой я только успел привыкнуть.
Простым пользователям, считающим компьютеры магией, проще понять, что «чего-то нет», чем понять «обнаружено 0 чего-то». Почитайте разговоры этих самых пользователей с техподдержкой (:
Я за разделение интерфейсов для «крутых» и обычных пользователей. Крутым — «0 записей в базе», обычным — «ничего не найдено». По умолчанию интерфейс делать «обычным», в настройки кинуть галочку — «интерфейс для опытных пользователей» или «расширенный интерфейс».
где почитать? они прямо так и пишут «у вас написано что найдено 0 записей, но ни одной записи ведь не найдено?!?! а-а-а, у меня кипит мозг!»?

ноль проходят в начальной школе. ЛЮБОЙ человек его понимает. даже совсем отсталый. а возмущает это лишь числоненавистников.
Неплохо бы в такие функции добавлять опциональный вариант на случай, если число — 0. Чтобы не писать «0 ответов», а «Ответов нет».
Накатал за пару часиков. Правила конечно же не все заложил, да и это работа не одного дня. Но все же: dvx-dev.ru/plural.php
Вводим слово в именительном падеже (в ед. числе, разумеется). Можно добавить прилагательное впереди.
php-ника хлебом не корми, дай написать велосипед.

а ведь еще в двадцатом веке люди придумали gettext
на геттексте свет клином не сошёлся. тем более что ngettext не поддерживает русский язык.
>ngettext не поддерживает русский язык.

в php какой-то особый ngettext, в котором традиционно ничего не работает?
самый обычный. в качестве параметров она везде принимает лишь 2 формы. писать на английском языке приложение рассчитанное прежде всего на русскоязычную аудиторию, а потом отдавать переводчикам переводить обратно на русский — весьма глупо.
>писать на английском языке приложение рассчитанное прежде всего на русскоязычную аудиторию, а потом отдавать переводчикам переводить обратно на русский — весьма глупо.

это проблемы вашего техпроцесса, а не функции gettext.

можно задать произвольное количество plural forms и формулу их выбора. в русском языке их три и ngettext прекрасно это обрабатывает
у нас нет проблем с техпроцессом именно потому что геттекст не используется

char * ngettext (const char * msgid, const char * msgid_plural, unsigned long int n);

где ты тут узрел 3 формы? или предлагаешь писать в коде 2 формы, а третюю пусть приписывают переводчики?
>или предлагаешь писать в коде 2 формы, а третюю пусть приписывают переводчики?

это можно сделать дофигищей разных способов без оверхеда с двойным переводом. тот же .po файл для русского языка можно генерировать по исходному коду.

тем не менее, писать в коде русские сообщения и завязываться на фиксированное количество plural forms — моветон, ящитаю.
каким таким образом можно генерировать по исходному коду русские тексты, если в исходниках можно указать лишь 2 формы?

то есть завязываться на английский и 2 формы — это нормально, а на русский и 3 формы — моветон? х)
>каким таким образом можно генерировать по исходному коду русские тексты, если в исходниках можно указать лишь 2 формы?

напрягите фантазию

>то есть завязываться на английский и 2 формы — это нормально, а на русский и 3 формы — моветон?

у меня резист от троллинга на плюс пицот.

вариант «английский в коде, русский в .po файле» — определенно лучше «русский в коде, что делать дальще — непонятно»
резист от интеллекта у тебя тоже зашкаливает…
ну то есть как локальное решение, чисто для русского языка — можно и свой велосипед, но это именно непортабельное локальное решение — по сути, грязный хак, мешающий нормальной локализации.
Супер, спасибо автору! Давно мечтал о таком решении (перенес в свои проекты).
А вообще, автор, НА ХУЙ С ХАБРА!
Откуда у него такая карма, господи?! На чем он поднялся?
залоговые аукционы
Наверное, англо-язычные роботы не палились.
Вот в одну строчку
public static function make($n, $form_1, $form_2, $form_3){
return ($n%10==1&&$n%100!=11? $form_1 :($n%10>=2&&$n%10<=4&&($n%100<10||$n%100>=20)? $form_2: $form_3));
}
угу. А теперь попробуем просклонять:
1 год; 2,3,4 года; 5,6,7,8,9 лет

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

Ext.util.Format.wformat = function(number,forms){
        var n = parseInt(number,10);
        var nplurals=3;
        var plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
        plural = (n==0)?0:plural + 1;
        if(forms.length > plural) return forms[plural].replace("$",n);
        return "";
    }

Собственно эта функция помещена в обьект Ext.util.Format для того чтобы ее можно было использовать в Шаблонах ExtJs вот так

var tpl = new Ext.XTemplate('{year:(["нет","Один год","$ года","$ лет"])}');

Ну и конечно не кто не заприщает ее использовать и без шаблонов :)
И никто, никто не вспомнил про ngettext(), который старше большинства из нас. И прямо в википедии есть уже готовая реализация кода.
Кстати, а его всегда на хостингах включают?
Что касаемо вообще gettext, останавливает от его использования формат библиотек, усложнённо как-то всё, с компилированием.
>останавливает от его использования формат библиотек, усложнённо как-то всё, с компилированием.

вот он — php-way! проще навелосипедить, чем разобраться в стандартном решении.

>с компилированием.

конечно с компилированием, не парсить же каталог при каждом вызове, CPU time на шаред-хостинке халявный, да?
Стандартное решение не всем и не всегда подходит, зачастую велосипед лучше.
причины «объективно не подходит» и «проще навелосипедить» — немного разные.
Невозможность работы решения на хостинге, где PHP собран без поддержки gettext — для меня лично более чем объективная причина. Проще и, я думаю, правильнее, дать пользователю возможность работать с CMS (например) не заставляя его переписываться с хостером (а сперва он напишет разработчику, или просто плюнет на «не рабочее» решение).
У Яндекса есть публичный сервис — "Склонятор". Возможно, в данном случае это как стрельба из пушки по воробьям, но, надеюсь, кому-нибудь прочитавшему это пригодится.
Думается мне, можно написать под этот сервис универсальную обёртку на java.
Во-первых, это у меня не работает, во-вторых, я имел в виду вывод текста, связанного с числительными, автоматом через склонятор. То есть, например, брать в некую обёртку число и существительное, а выдавать и то и то в нужной форме — не через формы ввода, а прямо на генерируемой странице.
Я не проверял, просто вспомнил. Скорей всего Яндекс забанил доступ к своим сервисам от IP Yahoo Pipes, потому и сломалось. А там вроде как раз так и было сделано.
У меня так:

/**
 * Функция склонения числительных в русском языке
 *
 * @param int    $number Число которое нужно просклонять
 * @param array  $titles Массив слов для склонения
 * @return string
 **/
function DigitCase($number, $titles)
{
	//отсекаем минусовые значения
	$number = str_replace("-","",$number);
        $cases = array (2, 0, 1, 1, 1, 2);
        return $titles[ ($number%100>4 && $number%100<20)? 2 : $cases[min($number%10, 5)] ];
}
На жабе для склонения дней:
public class Misc {
  public static String getDayText (int numberOfDays) {
    int x;
    x = numberOfDays % 100;
    if (> 20) {
       x = x % 10;
    }
    if (> 4) {
       return "дней";
    } else {
       switch (x) {
         case 1: return "день";
         case 0: return "дней";
         default: return "дня";
       }
    }
}
Случайно наткнулся на тему, дополню на Obj-C:

-(NSString *)units:(int)num cases:(NSArray *)cases {
num = abs(num);
NSString *word = @"";
word = (
num % 10 == 1 && num % 100 != 11
? [cases objectAtIndex:0]
: num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20)
? [cases objectAtIndex:1]
: [cases objectAtIndex:2]
);

return word;
}
Интересный подход. Теперь буду везде использовать это. Раньше в основном писал с ограничением до 10 обычным switch/case.
Пример под Python, если нужно кому-то, конечно.

number = 129

word = ["комментарий", "комментария", "комментариев"]

def get_com(x, y):
    inumber = x % 100
    if inumber >= 11 and inumber <=19:
        y = y[2]
    else:
        iinumber = inumber % 10
        if iinumber == 1:
            y = y[0]
        elif iinumber == 2 or iinumber == 3 or iinumber == 4:
            y = y[1]
        else:
            y = y[2]
    print(x, y)

get_com(number, word)

С обработчиком числа 0 и выводом Числа, пробела, слова

def get_com(x, y):
    if x == 0:
        return "нет комментариев"
    else:
        inumber = x % 100
        if inumber >= 11 and inumber <=19:
            y = y[2]
        else:
            iinumber = inumber % 10
            if iinumber == 1:
                y = y[0]
            elif iinumber == 2 or iinumber == 3 or iinumber == 4:
                y = y[1]
            else:
                y = y[2]
        return str(x) + " " + y
Only those users with full accounts are able to leave comments. Log in, please.