Обращаю ваше внимание на то, что эта запись является архивной. Ей уже больше 4 лет. Это означает, во-первых, то, что мое мнение по поднятым в ней вопросам могло измениться (хотя, конечно, не обязательно), а во-вторых, то, что я не испытываю никакого желания эти вопросы обсуждать, и поэтому комментарии и оценки я отключил.
Довольно часто бывает нужно вывести количество чего-то — например, просмотров или комментариев. Но морфология русского языка (и других славянских языков) такова, что окончание слова зависит от относящемуся к нему числа. То есть:
Некоторые не обращают на это внимания и используют на все числа одно слово. Это приводит к безграмотному составлению предложений. Лично мне неприятно читать словосочетание «1 комментариев».
Есть еще такой вариант:
Это неплохой вариант, хотя сразу возникает ощущение, что сайтом занимается не живой человек, а робот. А если нужно вывести список, то это однообразие выглядит не очень красиво и от двоеточий начинает рябить в глазах.
На самом деле, очень легко написать функцию, с помощью которой можно использовать красивые и морфологически правильные словосочетания. Вот она:
function morph($value)
{
if (preg_match('/1\d$/', $value))
return 2;
elseif (preg_match('/1$/', $value))
return 0;
elseif (preg_match('/(2|3|4)$/', $value))
return 1;
else
return 2;
}
// массив производных от слова, которое нужно вывести, в порядке один, два, много
$text = array('просмотр', 'просмотра', 'просмотров');
// номер, к которому относится слово
$number = 246;
// выводим правильное словосочетание
echo $number.' '.$text[morph($number)];
Также есть вариант, в котором массив вариантов склоняемого слова передается аргументом функции (спасибо за совет vasa_c):
function morph($value, $words, $separator = ' ')
{
if (preg_match('/1\d$/', $value))
return $value.$separator.$words[2];
elseif (preg_match('/1$/', $value))
return $value.$separator.$words[0];
elseif (preg_match('/(2|3|4)$/', $value))
return $value.$separator.$words[1];
else
return $value.$separator.$words[2];
}
$number = 251;
echo morph ($number, array('просмотр', 'просмотра', 'просмотров'));
И дополнительно вариант, когда аргументами передаются сами слова:
function morph($value, $word0, $word1, $word2, $separator = ' ')
{
if (preg_match('/1\d$/', $value))
return $value.$separator.$word2;
elseif (preg_match('/1$/', $value))
return $value.$separator.$word0;
elseif (preg_match('/(2|3|4)$/', $value))
return $value.$separator.$word1;
else
return $value.$separator.$word2;
}
$number = 317;
echo morph ($number, 'просмотр', 'просмотра', 'просмотров');
Еще предлагаю усложненный вариант Евгения Гетманенко (подробнее о своей функции он пишет в комментарии ниже):
<?php
function morph($value, $gender = '', $declension = '')
{
if (preg_match('/1\d$/', $value))
$n = 2;
elseif (preg_match('/1$/', $value))
$n = 0;
elseif (preg_match('/(2|3|4)$/', $value))
$n = 1;
else
$n = 2;
if ($gender == 'masculine') {
$ends = array(1 => array('', 'а', 'ов'), 2 => array('ь', 'я', 'ей'));
return $ends[$declension][$n];
} elseif ($gender == 'feminine') {
$ends = array(1 => array('а', 'и', ''), 3 => array('ья', 'ьи', 'ей'));
return $ends[$declension][$n];
} elseif ($gender == 'neuter') {
$ends = array('е', 'я', 'й');
return $ends[$n];
} else {
return $n; // Работает по тому же принципу, что в примере из статьи — нужно скормить эту переменную в массив
}
}
$posts = rand(1, 1000);
print 'На форуме оставлено '.$posts.' сообщени'.morph($posts, 'neuter').'.';
?>Вот и все, теперь можно выводить фразы человеческим языком :-).
Спасибо Евгению Гетманенко за идею :-).
Евгений, 20-го июля 2008 года в 01:54
<Код в статье>
Данная функция в 90% случаев не требует придумывать массивы. Скормить нужно число, род существительного, склонение (для среднего рода не нужно) и окончание подбирается автоматически. Функцию можно расширить для прилагательных и для всех падежей :-). Для слов, изменяемых каким-либо особенным образом, можно сделать по-старому (просто не отдавайте второй и третий параметры функции).
sap, 20-го июля 2008 года в 02:11
Спасибо за дополнение. Перенес код в статью, если ты не против :-).
sap, 20-го июля 2008 года в 13:27
Дополнил статью еще несколькими вариантами.
Сергей, 22-го декабря 2009 года в 15:23
Есть функция с двумя аргументами - число и слово - проще не придумаешь! Вот форма для тестирования: http://morpher.ru/DemoSoglasovanie.aspx
Функция доступна через веб-сервис или в виде DLL.