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соловьев
	}
	/* remove consonat from root */
	//$
	//День, лев, лёд, лён, лоб, мох, пень, пёс, ров, рот, сон, шов
	//Рожь, ложь, вошь.
	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('code/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?>
буржуа [m] -- [0] буржуы (need - буржуа) -- [1] буржу (need - буржуа)
кофе [n] -- [0] кофя (need - кофе) -- [1] кофей (need - кофе)
октябренок [m] -- [0] октябренка (need - октябренка) -- [1] октябренков (need - октябрят)
котенок [m] -- [0] котенка (need - котенка) -- [1] котенков (need - котят)
щенок [m] -- [0] щенка (need - щенка) -- [1] щенков (need - щенят)
вошь [f] -- [0] воши (need - вши) -- [1] вошей (need - вшей)
ухо [n] -- [0] уха (need - уха) -- [1] ух (need - ушей)
глаз [m] -- [0] глаза (need - глаза) -- [1] глазов (need - глаз)
волос [m] -- [0] волоса (need - волоса) -- [1] волосов (need - волос)
лев [m] -- [0] лева (need - льва) -- [1] левов (need - львов)
лёд [m] -- [0] лёда (need - льда) -- [1] лёдов (need - льдов)
лён [m] -- [0] лёна (need - льна) -- [1] лёнов (need - льнов)
лоб [m] -- [0] лоба (need - лба) -- [1] лобов (need - лбов)
пёс [m] -- [0] пёса (need - пса) -- [1] пёсов (need - псов)
ров [m] -- [0] рова (need - рва) -- [1] ровов (need - рвов)
сон [m] -- [0] сона (need - сна) -- [1] сонов (need - снов)
шов [m] -- [0] шова (need - шва) -- [1] шовов (need - швов)
рожь [f] -- [0] рожи (need - ржи) -- [1] рожей (need - ржей)
ложь [f] -- [0] ложи (need - лжи) -- [1] ложей (need - лжей)
вошь [f] -- [0] воши (need - вши) -- [1] вошей (need - вшей)
ноль cайтов
десять заказов
девять товаров
семнадцать пользователей
четыре файла
три модератора
пять приложений
семь билетов
шестнадцать дел
десять комментов
три комментария
четыре страницы
четырнадцать постов
шестнадцать записей
двенадцать мегабайтов
пять голосов
пять нетопырей
одинадцать цапель
двадцать зуев
двенадцать филинов
шестнадцать сов
пятнадцать птенцов
два сона
одинадцать стонов
ноль клинов
четырнадцать блинов
Неверно: 22 хлеба
Следует: 22 куска хлеба