Склоняем фамилию на PHP

Некоторое время назад, в очередном проекте, задался целью обращение к пользователям ставить в соответствующий падеж. Например, во фразе «Вам пришло письмо от Васи Пупкина», фамилия и имя стоят в Родительном падеже. Это получается красиво, а главное очень удобно. В то же время пользователю безумно приятно видеть, что программа правильно обращается к нему по имени. Задавшись целью, я не стал сломя голову писать все с нуля, а решил сначала поискать наработки других программистов на этом поприще. Поиски увенчались переменным успехом.

Результаты поисков
Сразу же нашлись несколько скриптов для склонения английских фамилий. Их я немедленно отбросил, поскольку мне нужно было склонение русских фамилий. За ними нашел библиотеки для 1С, Delphi и FoxPro. Но, в конце концов, и мне сопутствовала удача. Нашел одну относительно неплохую библиотеку на php. Скачать ее можно здесь.

Последней интересной находкой по этой теме, были отличыные сервисы Морфер.ру и Яндекс.Склонятор, но об этом ниже.

Найденная библиотека
Найденная библиотека в комментариях не поведала мне о своем наименовании. Архив называется names, но я предлагаю именовать его RussianNameProcessor, по имени основного класса. Сама библиотека срабатывает верно приблизительно в 90-95% случаев, что само по себе достаточно много.

В архиве есть файл для тестирования testNames.php, который объясняет, как работать с библиотекой.

testNames.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
include ("./names.php");
$a = new RussianNameProcessor(
'Козлов Евгений Павлович');      // годится обычная форма
echo "".$a->fullName($a->gcaseRod);
$a = new RussianNameProcessor(
'Евгений Павлович Козлов');      // в таком виде тоже
echo "<br/>".$a->fullName($a->gcaseRod);
$a = new RussianNameProcessor('Козлов', 
'Евгений');        // можно явно указать составляющие
echo "<br/>".$a->fullName($a->gcaseRod);
$a = new RussianNameProcessor('Кунтидия', 
'Убиреко', '', 'f'); // можно явно указать пол ('m' или 'f')
echo "<br/>".$a->fullName($a->gcaseRod);
$a = new RussianNameProcessor('Козлова Евгения Павловна');
echo "<br/>".$a->fullName($a->gcaseRod);
?>

Соответственно видим следующий текст.

В родительном падеже стоят прекрасно

Итак, подключив файл names.php, с помощью include, создаем объект класса RussianNameProcessor. Этот класс является основным и через него идет вся работа. Конструктор объявлен следующим образом:

function RussianNameProcessor (string $lastName, 
string $firstName = NULL, string $middleName = NULL, 
string $sex = NULL)

Как видите, в конструктор обязательно нужно передать первый параметр – фамилию. Можно также первым параметром передать строку с фамилией, именем и отчеством, как показано в примере выше.

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

  • string $lastName – фамилия. Может быть указана строка с фамилией, именем и отчеством;
  • string $firstName – имя. По умолчанию равно NULL;
  • string $middleName – отчество. По умолчанию равно NULL;
  • string $sex – пол. Может принимать значение «m» что значит мужской пол или «f» что значит женский пол. По умолчанию равно NULL.

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

string fullName( string $gcase)

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

  • $RussianNameProcessor->gcaseIm или $RussianNameProcessor->gcaseNom – именительный падеж;
  • $RussianNameProcessor->gcaseRod или $RussianNameProcessor->gcaseGen – родительный падеж;
  • $RussianNameProcessor->gcaseDat – дательный падеж;
  • $RussianNameProcessor->gcaseVin или $RussianNameProcessor->gcaseAcc – винительный падеж;
  • $RussianNameProcessor->gcaseTvor или $RussianNameProcessor->gcaseIns – творительный падеж;
  • $RussianNameProcessor->gcasePred или $RussianNameProcessor->gcasePos – предложный падеж.

Есть также несколько функций для склонения отдельных составляющих:

  • string lastName(string $gcase) – метод склоняет отдельно фамилию;
  • string firstName(string $gcase) – метод склоняет отдельно имя;
  • string middleName(string $gcase) – метод склоняет отдельно отчество.

В эти методы падеж передается точно также как и в метод fullName, т.е. с помощью указанных выше свойств класса RussianNameProcessor.

Хочу отдельно заметить, что эта библиотека настроена так, что хорошо склоняет русские фамилии, записанные в кодировке windows-1251.

Для того чтобы склонять фамилии, записанные в UTF-8, нужно сделать некоторые преобразования.

Во-первых, нужно перекодировать файл names.php в кодировку UTF-8. Сделать это можно в любом нормальном редакторе, рекомендую Notepad++, который можно скачать где угодно, да хотя бы здесь.

Во-вторых, нужно в php настроить перегрузку строковых функций, функциями из расширения mb_string (не забудьте его сначала активировать). Для этого в php.ini напишите mbstring.func_overload = 7.

Теперь можно склонять фамилии, записанные в UTF-8. Для примера можно немного переделать файл testNames.php, перекодировав его в UTF-8.

testNamesUTF.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
header('Content-type:text/html;charset=UTF-8');
//внутреннюю кодировку поставим в утф
mb_internal_encoding("UTF-8");
include ("./names.php");
$a = new RussianNameProcessor(
'Козлов Евгений Павлович');      // годится обычная форма
echo "".$a->fullName($a->gcaseRod);
$a = new RussianNameProcessor(
'Евгений Павлович Козлов');      // в таком виде тоже
echo "<br/>".$a->fullName($a->gcaseRod);
$a = new RussianNameProcessor('Козлов', 
'Евгений');        // можно явно указать составляющие
echo "<br/>".$a->fullName($a->gcaseRod);
$a = new RussianNameProcessor('Кунтидия', 
'Убиреко', '', 'f'); // можно явно указать пол ('m' или 'f')
echo "<br/>".$a->fullName($a->gcaseRod);
$a = new RussianNameProcessor('Козлова Евгения Павловна');
echo "<br/>".$a->fullName($a->gcaseRod);
?>

При этом видим ту же картину

В UTF-8 все слова были поставлены верно

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

Морфер.ру
Теперь перейдем к сервисам.

Кого по каким-либо причинам не устаивает вышеописанная библиотека, может использовать специальные сервисы для склонения фамилий и слов. Начнем описание с сервиса morpher.ru.

Этот сервис был разработан и поддерживается программистом Сергеем Слеповым. Разработанная технология отличная и умеет многое:

  • склонять слова на русском;
  • склонять слова на украинском;
  • писать сумму прописью;
  • склонять слова в единственном и множественном числе;
  • и многое другое.

Сервис представляет собой следующую структуру: обратившись к определенному URL, передав через get или post слово, которое нужно просклонять, получим XML-файл с результатом.

Для примера, я написал небольшой класс для работы с этим сервисом по протоколу HTTP (ещё этот сервис поддерживает SOAP). Скачать этот класс можно отсюда.

Вот небольшой пример работы с этим классом

testMorpher.php

1
2
3
4
5
6
7
8
9
10
11
<?php
//подключаем класс
include_once 'morpher.php';
//отправляем заголовки
header('Content-type:text/plain;charset=UTF-8');
//создаем объект класса
$m = new Morpher(mb_convert_encoding(
'Вася Пупкин','UTF-8','windows-1251'));
//получаем склонение
var_dump($m->getInflect());
?>

В конструктор класса передается слово, которое нужно просклонять, в кодировке UTF-8.

Для того чтобы получить склонение, нужно вызвать метод getInflect(). Этот метод вернет массив со словами в соответствующих падежах либо false, если произошла ошибка.

Сервис позволяет делать не более 100 одинаковых запросов в сутки и не более 1000 запросов в сутки всего. Правда существуют платные варианты, в которых нет данных ограничений.

Яндекс.Склонятор
У Яндекса есть специальная площадка для того, чтобы сотрудники компании могли размещать свои проекты в сети. Эта площадка называется Яндекс.Нано. Среди всех проектов, расположенных на Яндекс.Нано, есть один, который предназначен для склонения фамилий. Он имеет название Яндекс.Склонятор.

Этот сервис чуть-чуть похуже, чем предыдущий. Верность склонения составляет приблизительно 90% (например, мою фамилию неверно поставил в винительный падеж).

Работает этот сервис приблизительно по такой же схеме, что и предыдущий. Единственное отличие Яндекс.Склонятора в том, что он может возвращать данные не только в xml-формате, но еще и в формате json.

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

testYandex.php

1
2
3
4
5
6
7
8
9
10
11
<?php
//отсылаем заголовки
header('Content-type:text/plain;charset=UTF-8');
//подключаем класс
include_once 'yandex_inflect.php';
//создаем объект
$y = new YandexInflect(mb_convert_encoding(
'Вася Пупкин','UTF-8','windows-1251'),'json');
//получаем склонение
var_dump($y->getInflect());
?>

В конструктор класса передаем слово, которое нужно просклонять в UTF-8, а также наименование формата, в котором будем запрашивать данные у Яндекса: xml или json. По умолчанию установлено в xml.
Метод getInflect() вернет массив со словами в падежах.
Про ограничения этого сервиса ничего не сказано, но я уверен, что такой сервис без ограничений в количестве запросов не обойдется.

Популярность: 12%


Интересное из других блогов:

2leep.com

И не забывайте комментировать статью.

Добавляйся в группу во вконтакте, чтобы самым первым узнавать все новости сайта

Отзывов: 19 на «Склоняем фамилию на PHP»

  1. Автор: slon1024, 23 августа 2010 в 12:26

    использует Firefox 3.0.17 Firefox 3.0.17 на Ubuntu 8.10 Ubuntu 8.10

    Спасибо, понравилась статья. Мне больше всего приглянулся яндекс “Склонятор”.

    Кстати, у яндекса есть что-нибудь похожее для работы с синонимами? Например, пишу слова “дом” и получаю резльтат “здание, дворец, изба, хата, хижина, землянка, лачуга, мазанка, палата, хоромы, терем…”

    • Автор: web-junior, 23 августа 2010 в 12:44

      использует Firefox 3.5.9 Firefox 3.5.9 на Windows XP Windows XP

      Пожалуйста! Заходите еще!

      По поводу синонимов: я пока что не встречал у яндекса такого сервиса.

  2. Автор: AlterVision, 29 августа 2010 в 09:26

    использует Opera 10.61 Opera 10.61 на Windows 7 Windows 7

    Я как-то столкнулся со схожей задачей, но решал проблему намного проще, без классов и всего подобного наворота, всего лишь двумя функциями. Никакого JSON при этом не применялось, всё на полном минимализме. Может такой подход окажется лучше? Или есть определённые преимущества именно у JSON-технологии?
    Вот моя мысль, как всё этосделать: http://www.av13.ru/creative/real-name-inflection-in-web/ – что скажете?

    • Автор: web-junior, 29 августа 2010 в 12:05

      использует Firefox 3.5.9 Firefox 3.5.9 на Windows XP Windows XP

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

  3. Автор: Beagler, 21 ноября 2010 в 18:40

    использует Opera 10.63 Opera 10.63 на Windows XP Windows XP

    хм, как-то не удалось заставить работать RussianNameProcessor в UTF-8

    • Автор: web-junior, 21 ноября 2010 в 22:13

      использует Firefox 3.6.12 Firefox 3.6.12 на Windows 7 Windows 7

      А как проявляется неработоспособность?

  4. Автор: Beagler, 22 ноября 2010 в 10:52

    использует Opera 10.63 Opera 10.63 на Windows XP Windows XP

    А просто не склоняет – возвращает то, что было на входе.

    • Автор: web-junior, 22 ноября 2010 в 11:34

      использует Firefox 3.6.12 Firefox 3.6.12 на Windows 7 Windows 7

      какая версия php? может с mb_string проблемы?

  5. Автор: Beagler, 22 ноября 2010 в 12:08

    использует Opera 10.63 Opera 10.63 на Windows XP Windows XP

    5.2.8
    mb_string включен

    • Автор: web-junior, 22 ноября 2010 в 12:29

      использует Firefox 3.6.12 Firefox 3.6.12 на Windows 7 Windows 7

      а перегрузка строковых функций функциями из mb_string?

  6. Автор: Beagler, 22 ноября 2010 в 12:40

    использует Opera 10.63 Opera 10.63 на Windows XP Windows XP

    неа
    нет доступа к php.ini

    • Автор: web-junior, 23 ноября 2010 в 10:15

      использует Firefox 3.6.12 Firefox 3.6.12 на Windows 7 Windows 7

      тогда перекодируйте склоняемый текст перед склонением в windows-1251, а после склонения – обратно в UTF-8 или используйте сервисы, о которых рассказано в статье.

  7. Автор: Beagler, 23 ноября 2010 в 10:17

    использует Opera 10.63 Opera 10.63 на Windows XP Windows XP

    спасибо. Попробую использовать iconv

  8. Автор: Андрей, 5 января 2011 в 17:23

    использует Firefox 3.6.13 Firefox 3.6.13 на Windows XP Windows XP

    А как быть с фамилиями, которые по правилам не склоняются?

    • Автор: web-junior, 10 января 2011 в 19:18

      использует Firefox 3.6.12 Firefox 3.6.12 на Windows 7 Windows 7

      Здравствуйте.
      К сожалению, пока что не разработано адекватного решения для корректного склонения фамилий, которые не склоняются по правилам.

    • Автор: Alexander, 23 июля 2011 в 11:25

      использует Opera 10.63 Opera 10.63 на Windows XP Windows XP

      Конечно, можно найти своё решение – написать обьект, который бы имел в себе функцию сравнения фамилии с введённой. В масив можно поместить эти фамилии. Их там и не столько уж и много. А потом просто сравнивать элементы такого масива с введённой фамилией.

RSS-лента комментариев. Адрес для трекбека

Ваш отзыв

Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

Нажимая на кнопку "Добавить" вы принимаете правила комментирования