Count russian nouns with correct declination/pluralization (Счет существительных в русском языке)

<?php
 
function ru_noun_genetive($word, $gender, $plural) {
	/* Apply "go archaic" mutation! */
	if ($gender == 'f') {
			$word = preg_replace ( "/([^ср])ть$/u", "$1терь" , $word );
			$word = preg_replace ( "/чь$/u", "$1черь" , $word );
	}
 
	/* Masculine words that look feminine (SUPER HACK!) */
	if ($gender == 'm' && preg_match( "/(а|я)$/u", $word)) $gender = 'f'; 
 
	/* Apply endings ('The Rules') */
	if (!$plural) { //genetive case / singular
		if ($gender == 'm') {
			$word = preg_replace ( "/([^аеийоуьыэюя])$/u", "$1а" , $word );
			$word = preg_replace ( "/й$/u", "я" , $word );
			$word = preg_replace ( "/ь$/u", "я" , $word );
		}
		if ($gender == 'f') {
			$word = preg_replace ( "/а$/u", "ы" , $word );			
			$word = preg_replace ( "/ь|я$/u", "и" , $word );
		}
		if ($gender == 'n') {
			$word = preg_replace ( "/о$/u", "а" , $word );
			$word = preg_replace ( "/е$/u", "я" , $word );
		}
	}
	if ($plural) { //genetive case / plural
		if ($gender == 'm') {
			$old_word = $word;
			$word = preg_replace ( "/й$/u", "ев" , $word);
			$word = preg_replace ( "/([жчшщ])$/u", "$1ей" , $word);			
			$word = preg_replace ( "/(ц)$/u", "$1ев", $word);
			$word = preg_replace ( "/ь$/u", "ей" , $word);
			if ($word == $old_word) 
				$word = preg_replace ( "/([^аеиоуэюя])$/u", "$1ов" , $word);
		}
		if ($gender == 'f') {
			$word = preg_replace ( "/([^аеиоуэюя])я$/u", "$1ь" , $word );
			$word = preg_replace ( "/([аеиоуэюя])я$/u", "$1й" , $word );
			$word = preg_replace ( "/а$/u", "" , $word );
			$word = preg_replace ( "/ь$/u", "$1ей" , $word );
		}
		if ($gender == 'n') {
			$word = preg_replace ( "/о$/u", "" , $word );
			$word = preg_replace ( "/ие$/u", "ий" , $word );
			$word = preg_replace ( "/е$/u", "ей" , $word );
		}
	}
 
	/* Apply "consonant expansion" mutation */
	if ($gender == 'n') {
			$word = preg_replace ( "/кн$/u", "кон" , $word );
	}
	if ($gender == 'n') {
		if (!$plural) {
			$word = preg_replace ( "/мя$/u", "мени" , $word );
		}
		if ($plural) {
			$word = preg_replace ( "/мя$/u", "мён" , $word );
			$word = preg_replace ( "/сл$/u", "сел" , $word );
		}
		/* Apply 'flavor' */
			$word = preg_replace ( "/ця$/u", "ца" , $word );//singular
			$word = preg_replace ( "/([цщ])ей$/u", "$1" , $word );//plural
			$word = preg_replace ( "/([с])емён$/u", "$1емян" , $word );//plural	
	}
	/* Apply "Double consonant" mutation */
	if ($gender == 'f' || $gender == 'n') {
		if ($plural) {
			$word = preg_replace ( "/е([чршт])к$/u", $1ок" , $word ); //femin
			$word = preg_replace ( "/([чршт])к$/u", "$1ек" , $word ); //neuter
			$word = preg_replace ( "/([лмн])к$/u", "$1ок" , $word );
			$word = preg_replace ( "/([к])л$/u", "$1ол" , $word );
		}
	}
	/* Apply Palatalization */
	if ($gender == 'm' || $gender == 'f') {
			$word = preg_replace ( "/([дт])([ея])([дт])ей$/u", "$1$2$3ь" , $word );//1
	}
	if ($gender == 'm') {
			$word = preg_replace ( "/еней$/u", "ней" , $word );//1
			$word = preg_replace ( "/еня$/u", "ня" , $word );//0
 
			$word = preg_replace ( "/ецев$/u", "цов" , $word );//1
			$word = preg_replace ( "/еца$/u", "ца" , $word );//0
 
			$word = preg_replace ( "/оков$/u", "ков" , $word );//1
			$word = preg_replace ( "/ока$/u", "ка" , $word );//0
 
			//моха-мха мохов-мхов
			$word = preg_replace ( "/охов$/u", "хов" , $word );//1
			$word = preg_replace ( "/оха$/u", "ха" , $word );//0
 
 
			$word = preg_replace ( "/(р)отов$/u", "$1тов" , $word );//1
			$word = preg_replace ( "/(р)ота$/u", "$1та" , $word );//0
 
		if ($plural) {
			/* Handle "chibi suffix" */
			$word = preg_replace ( "/ёнков$/u", "ят" , $word );
			/* Make softer sound */
			$word = preg_replace ( "/(коло)сов$/u", "$1сьев" , $word );
			$word = preg_replace ( "/([^аеиоуэюя])(р[а])тов$/u", "$1$2тьев" , $word );
			$word = preg_replace ( "/зей$/u", "зьев" , $word );
			$word = preg_replace ( "/([е])ртов$/u", "$1ртей" , $word );
			$word = preg_replace ( "/ынов$/u", "ыновей" , $word );//1			
		}
		$word = preg_replace ( "/лия$/u", "лья" , $word );//0 -2улия -2улья
		$word = preg_replace ( "/ея$/u", "ья" , $word );//0 -2соловея -2соловья
		$word = preg_replace ( "/еев$/u", "ьев" , $word );//1 -5соловеев -5соловьев
	}
	if ($gender == 'n') {
			$word = preg_replace ( "/ев$/u", "евьев" , $word );//1 деревев -- деревьев
			$word = preg_replace ( "/(.)рыл$/u", "$1рыльев" , $word );//1крыл -- крыльев			
	}
	if ($gender == 'f') {
			$word = preg_replace ( "/пк$/u", "пок" , $word );//0
 
			$word = preg_replace ( "/([пм])лей$/u", "$1ель" , $word );//1
	}
 
	/* Apply Russian Spelling Rules */
	$word = preg_replace ( "/([гкхжчшщ])ы$/u", "$1и" , $word );
	$word = preg_replace ( "/([гкхжчшщ])я$/u", "$1а" , $word );
	$word = preg_replace ( "/([гкхжчшщ])ю$/u", "$1у" , $word );	
 
	/* Done! :) */
	return $word;// . "[$plural, $gender]";
}
 
function ru_noun_count($quantity, $word, $spell_number = 1) {
 
	static $s_list = array( 
		/* Never plural */
		"буржуа", "кофе"
	);
 
	$gender = ru_noun_gender($word);
 
	$mode = ru_number_case($quantity);
 
	if ($spell_number) $quantity = ru_number($quantity, $gender);
 
	if (in_array($word, $s_list)) $mode = 0;
 
	if ($mode) $word = ru_noun_genetive($word, $gender, $mode-1);
 
	return $quantity . " " . $word;
}
 
/* Unit test
 * Prepare 'testlist.txt' in format:
 * ночь ночи ночей\n */ 
$lines = split("\n", file_get_contents('../testlist.txt'));
foreach ($lines as $line) {
	list($word, $gs, $gp) = split(" ", $line);
 
	$gender = ru_noun_gender($word);
 
	$mgs = ru_noun_genetive($word, $gender, 0);
	$mgp = ru_noun_genetive($word, $gender, 1);
 
	if ($mgs != $gs || $mgp != $gp) {
		echo "$word [$gender] -- [0] $mgs (need - $gs) -- [1] $mgp (need - $gp)<BR>"; 
	}
} 
 
 
/* Sample */
 $words = array("cайт","заказ","товар","пользователь","файл",
 "модератор","приложение","билет","дело","коммент","комментарий",
 "страница","пост","запись","мегабайт","голос","нетопырь","цапля","зуй","филин","сова",
 "птенец");
 foreach ($words as $word) {
 	$number = rand(0, 20);
 	echo ru_noun_count($number, $word) . "<BR>"; 
 } 
 echo "Неверно: " .ru_noun_count(22, "хлеб", 0) . "      <BR>";
 echo "Следует: " .ru_noun_count(22, "кусок", 0) . " хлеба<BR>";
 
php?>
шесть cайтов
семь заказов
пять товаров
одинадцать пользователей
восемь файлов
шесть модераторов
семнадцать приложений
двенадцать билетов
девятнадцать дел
семь комментов
один комментарий
десять страниц
два поста
тринадцать записей
шестнадцать мегабайтов
один голос
пятнадцать нетопырей
одна цапля
один зуй
шесть филинов
восемь сов
один птенец
Неверно: 22 хлеба
Следует: 22 куска хлеба