Личный сайт Андрея Сабинина

Сайт не обновляется с начала 2011 года, так как у меня на это нет ни времени, ни желания.

Заглавная / Архив блога о разработке / Разработка / Морфология: окончания слов
 

Морфология: окончания слов

sap, 19-го июля 2008 года в 22:50

Обращаю ваше внимание на то, что эта запись является архивной. Ей уже больше 4 лет. Это означает, во-первых, то, что мое мнение по поднятым в ней вопросам могло измениться (хотя, конечно, не обязательно), а во-вторых, то, что я не испытываю никакого желания эти вопросы обсуждать, и поэтому комментарии и оценки я отключил.


Довольно часто бывает нужно вывести количество чего-то — например, просмотров или комментариев. Но морфология русского языка (и других славянских языков) такова, что окончание слова зависит от относящемуся к нему числа. То есть:

1 просмотр
2 просмотра
5 просмотров

Некоторые не обращают на это внимания и используют на все числа одно слово. Это приводит к безграмотному составлению предложений. Лично мне неприятно читать словосочетание «1 комментариев».

Есть еще такой вариант:

Просмотров: 3

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

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

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(=> array('''а''ов'), => array('ь''я''ей'));
        return 
$ends[$declension][$n];
    } elseif (
$gender == 'feminine') {
        
$ends = array(=> array('а''и'''), => array('ья''ьи''ей'));
        return 
$ends[$declension][$n];
    } elseif (
$gender == 'neuter') {
        
$ends = array('е''я''й');
        return 
$ends[$n];
    } else {
        return 
$n// Работает по тому же принципу, что в примере из статьи — нужно скормить эту переменную в массив
    
}
}

$posts rand(11000);

print 
'На форуме оставлено '.$posts.' сообщени'.morph($posts'neuter').'.';

?>

Вот и все, теперь можно выводить фразы человеческим языком :-).

Спасибо Евгению Гетманенко за идею :-).

 −3
+14 

Евгений, 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.