Склоняем имена на сайтах

Опубликовано 22.08.2010 в 00:29 в разделе

При разработке русскоязычных проектов, ориентированных на обычного пользователя, таких как социальные сети и сервисы, веб-программисты зачастую сталкиваются с задачей склонения имён пользователей, ников, географических названий и пр. Благодаря новому удобному сервису от Яндекс.Нано эта задача стала элементарной и тривиальной. Небольшой скрипт на PHP поможет Вам легко добавить функцию склонения имён собственных на свой сайт.

В дебрях пользовательских проектов Яндекс.Нано затесался  скромный, но очень полезный для русскоязычной аудитории проект Склонятор. Авторы характеризуют его так: «Веб-сервис, для разработчиков. Умеет склонять имена, фамилии и иногда даже ники». От себя хотел бы добавить лишь два слова: «превосходный» и «незаменимый», умеет склонять не только фамилии и имена, но и названия географических объектов и некоторые другие слова.

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

function inflect ( $name ) {

	// Building Request URL
	$url = 'http://export.yandex.ru/inflect.xml?name='.urlencode($name);

	// Processing CURL Request
	$curl = curl_init( $url );
	curl_setopt( $curl, CURLOPT_USERAGENT, 'Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.6.30 Version/10.61' ); // Just for fun, or ...
	curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
	$result = curl_exec( $curl );
	curl_close( $curl );

	// Preparing Inflections
	$cases = array ();
	preg_match_all( '#\<inflection\s+case\=\"([0-9]+)\"\>(.*?)\<\/inflection\>#si', $result, $m );

	// Creating Inflection List
	if ( count($m[0]) ) {
		foreach ( $m[1] as $i => &$id ) {
			$cases[ (int) $id ] = $m[2][$i];
		} unset ( $id );
	} else return null;

	// Sending Request Back to User
	if ( count( $cases ) > 1 ) {
		return $cases;
	} else return false;

}

Её использование элементарно — при вызове, функция inflect получает единственный параметр — склоняемое имя. Если имя не удалось просклонять (в случае отказа связи или несклоняемого имени) функция возвращает false или null. В случае успеха, функция возвращает массив имён пользователя в зависимости от падежа (с 1 по 6 номер). Результат получается в кодировке UTF-8.

Если немного доработать имеющуюся функцию, можно значительно повысить её быстродействие, добавив элементарное кэширование запросов к серверу. Дополнительно мы создаём константу INFLECT_CACHE, хранящую значение пути к файлам кэша запросов.

define ( 'ABSPATH', dirname(__FILE__).'/' );
define ( 'INFLECT_CACHE', ABSPATH . 'cache/inflect.%s.txt' );

function inflector ( $name ) {

	// Getting Cachable ID
	$nid = md5( $name );

	// Checking for Cached Version
	if ( file_exists(sprintf(INFLECT_CACHE, $nid)) ) {

		// Loading form Cache
		$cases = file_get_contents( sprintf(INFLECT_CACHE, $nid) );
		$cases = unserialize( $cases );
		return $cases;

	} else {

		// Building Request URL
		$url = 'http://export.yandex.ru/inflect.xml?name='.urlencode($name);

		// Processing CURL Request
		$curl = curl_init( $url );
		curl_setopt( $curl, CURLOPT_USERAGENT, 'Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.6.30 Version/10.61' ); // Just for fun, or ...
		curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
		$result = curl_exec( $curl );
		curl_close( $curl );

		// Preparing Inflections
		$cases = array ();
		preg_match_all( '#\<inflection\s+case\=\"([0-9]+)\"\>(.*?)\<\/inflection\>#si', $result, $m );

		// Creating Inflection List
		if ( count($m[0]) ) {
			foreach ( $m[1] as $i => &$id ) {
				$cases[ (int) $id ] = $m[2][$i];
			} unset ( $id );
		} else return false;

		// Saving Result and Sending back to User
		file_put_contents( sprintf(INFLECT_CACHE, $nid), serialize($cases) );
		return $cases;

	}

}

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

Рассмотрим пример работы скрипта с самым простым и привычным именем:

// Request for the Pupkin
inflect( 'Василий Иванович Пупкин' );
// The Result of Pupkin's
$inflection = array (
  1 => 'Василий Иванович Пупкин',
  2 => 'Василия Ивановича Пупкина',
  3 => 'Василию Ивановичу Пупкину',
  4 => 'Василия Ивановича Пупкина',
  5 => 'Василием Ивановичем Пупкиным',
  6 => 'Василии Ивановиче Пупкине',
);

Как видно из примера, функция сразу же даёт приятный положительный результат и склоняет полное Ф.И.О. без каких-либо проблем. Результат может легко использоваться в сочетании с простой функцией «имя пользователя», которая получает на вход имя и падеж.

function username( $name, $case = 1 ) {
	$cases = inflect( $name );
	if ( $cases && count( $cases ) > 1 ) {
		return $cases[$case];
	} else return $name;
}

Применяя в коде username(‘Вася’, 2) мы получим текст «Васе» и не будем более иметь проблем с падежами русских имён собственных, географических названий, ников и прочих слов.