ru_soundex()
хотелось бы узнать мнение сообщества: нужна ли народу такая функция? отправить ли её на офсайт пхп?
или народу не нужны нездоровые сенсации?
// (cc) me, 23/08/2007-27/08/2007
$str = “к скалам бурым”;
print “ru_soundex($str) = “.ru_soundex($str).“<br />\r\n”;
$str = “с каламбуром”;
print “ru_soundex($str) = “.ru_soundex($str).“<br />\r\n”;;
function ru_soundex($source)
{
$res = '';
$literal = array();
// ассоциативный массив букв
// параметры звуков гласный / согласный
// для гласных переход буквы в звук(и), редуцированный/нет, предполагаемые правила ударения исходя из кол-ва слогов (stressed syllable)
// реализована проверка предполагаемого ударения
// для согласных переход букв[ы] в звук(и), редуцируемый/нет, правила редуцирования
// vowel
$literal['А'] = array('status'=>'гласный','sound'=>'а','stressed'=>'а'); // никогда не меняется
$literal['Е'] = array('status'=>'гласный','sound'=>'и','stressed'=>'э', 'АаЕеЁёИиОоУуЭэЮюЯяЬьЫыЪъ' => 'йэ'); // - особые правила, для этой буквы, стоящей после указанных, а также в начале слов
$literal['Ё'] = array('status'=>'гласный','sound'=>'о','stressed'=>'о', 'АаЕеЁёИиОоУуЭэЮюЯяЬьЫыЪъ' => 'йо');
$literal['И'] = array('status'=>'гласный','sound'=>'и','stressed'=>'и');
$literal['О'] = array('status'=>'гласный','sound'=>'а','stressed'=>'о');
$literal['У'] = array('status'=>'гласный','sound'=>'у','stressed'=>'у');
$literal['Ы'] = array('status'=>'гласный','sound'=>'ы','stressed'=>'ы');
$literal['Э'] = array('status'=>'гласный','sound'=>'э','stressed'=>'э');
$literal['Ю'] = array('status'=>'гласный','sound'=>'у','stressed'=>'у', 'АаЕеЁёИиОоУуЭэЮюЯяЬьЫыЪъ' => 'йу');
$literal['Я'] = array('status'=>'гласный','sound'=>'а','stressed'=>'а', 'АаЕеЁёИиОоУуЭэЮюЯяЬьЫыЪъ' => 'йа'); // заяц произносится как [зайец]
$v_pattern = 'АаЕеЁёИиОоУуЭэЮюЯяЬьЫыЪъ';
// кстати, надо добавить выкусывание гласных из концов слов, заканчивающихся на согласный-гласный-звонкий согласный (-ром, -лем, итд) гласная очень часто сглатывается
// зы: это здесь не реализовано %)
// проверено: soundex и сам с этим неплохо справляется
// звонкие согласные редуцируются при удвоении.
// звонкие согласные переходят в парный глухой перед глухим
// глухие редуцируются полностью перед глухими.
// consonant
// в отличие от гласных, для согласных условие “стоит перед указанной или в конце слова”
$literal['Б'] = array('status'=>'согласный','sound'=>'б', 'КкПпСсТтФфХхЦцЧчШшЩщ' => 'п');
$literal['В'] = array('status'=>'согласный','sound'=>'в', 'КкПпСсТтФфХхЦцЧчШшЩщ' => 'ф');
$literal['Г'] = array('status'=>'согласный','sound'=>'Г', 'КкПпСсТтФфХхЦцЧчШшЩщ' => 'к');
$literal['Д'] = array('status'=>'согласный','sound'=>'д', 'КкПпСсТтФфХхЦцЧчШшЩщ' => 'т');
$literal['Ж'] = array('status'=>'согласный','sound'=>'ж', 'КкПпСсТтФфХхЦцЧчШшЩщ' => 'ш');
$literal['З'] = array('status'=>'согласный','sound'=>'з', 'КкПпСсТтФфХхЦцЧчШшЩщ' => 'с');
$literal['Й'] = array('status'=>'согласный','sound'=>'й');
$literal['К'] = array('status'=>'согласный','sound'=>'к', 'КкПпСсТтФфХхЦцЧчШшЩщ' => '');
$literal['Л'] = array('status'=>'согласный','sound'=>'л');
$literal['М'] = array('status'=>'согласный','sound'=>'м');
$literal['Н'] = array('status'=>'согласный','sound'=>'н');
$literal['П'] = array('status'=>'согласный','sound'=>'п', 'КкПпСсТтФфХхЦцЧчШшЩщ' => '');
$literal['Р'] = array('status'=>'согласный','sound'=>'р');
$literal['С'] = array('status'=>'согласный','sound'=>'с'); // а вот С не хочет редуцироваться, на первый взгляд…
$literal['Т'] = array('status'=>'согласный','sound'=>'т', 'КкПпСсТтФфХхЦцЧчШшЩщ' => '');
$literal['Ф'] = array('status'=>'согласный','sound'=>'ф', 'КкПпСсТтФфХхЦцЧчШшЩщ' => ''); // спорно
$literal['Х'] = array('status'=>'согласный','sound'=>'х');
$literal['Ц'] = array('status'=>'согласный','sound'=>'ц');
$literal['Ч'] = array('status'=>'согласный','sound'=>'чь'); // всегда мягкий
$literal['Ш'] = array('status'=>'согласный','sound'=>'ш');
$literal['Щ'] = array('status'=>'согласный','sound'=>'щь');
// спецсимволы
$literal['Ъ'] = array('status'=>'знак','sound'=>' '); // только разделительный. делит жёстко
$literal['Ь'] = array('status'=>'знак','sound'=>'ь'); // даже если делит, то мягко
$literal['ТС'] = array('status'=>'сочетание','sound'=>'ц');
$literal['ТЬС'] = $literal['ТС'];
$literal['ШЬ'] = array('status'=>'сочетание','sound'=>'ш'); // всегда твёрдый. и это не единстенный рудимент языка
$literal['СОЛНЦ'] = array('status'=>'сочетание','sound'=>'сонц');
$literal['ЯИЧНИЦ'] = array('status'=>'сочетание','sound'=>'еишниц');
$literal['КОНЕЧНО'] = array('status'=>'сочетание','sound'=>'канешно');
$literal['ЧТО'] = array('status'=>'сочетание','sound'=>'што');
$literal['ЗАЯ'] = array('status'=>'сочетание','sound'=>'зайэ'); // да-да. не только [зайэц], но и [зайэвльэнийэ]
$sound = str_to_upper($source);
// сначала сочетания
foreach( array_filter($literal,
create_function('$item','if( $item[”status”] === “сочетание”) return true; return false;'))
as $sign => $translate )
$sound = str_replace($sign,$translate[“sound”],$sound);
// потом знаки
foreach( array_filter($literal,
create_function('$item','if( $item[”status”] === “знак”) return true; return false;'))
as $sign => $voice )
$sound = str_replace($sign,$translate[“sound”],$sound);
// разделяем на слова, определяем кол-во слогов, заменяем ударный/безударный гласный (единственный или предполагая второй в двух-трёхсложном слове, предпредпоследний - в остальных)
$words = preg_split('~[,.\~`1234567890-=\~!@#$%^&*()_+|{}\]\];:\'”<>/? ]~', $sound, -1, PREG_SPLIT_NO_EMPTY);
// гласные
foreach( array_filter($literal,
create_function('$item','if( $item[”status”] === “гласный”) return true; return false;'))
as $sign => $translate )
{
// для каждого слова
foreach( $words as &$word )
{
// кол-во гласных
$vowel = preg_match_all(“~[$v_pattern]~”, $word, $del_me );
// готовим
$cur_pos = 0;
$cur_vowel = 0;
while( false !== $cur_pos = strpos($word,$sign,$cur_pos) )
{
$cur_vowel++;
// print $cur_pos.' = '.$sound[$cur_pos].”<br />\r\n”;
if( sizeof($translate)==4 && ($cur_pos === 0 || strpos( $v_pattern , $word[$cur_pos-1] )))
{
$word = substr_replace($word,$translate[$v_pattern],$cur_pos,1);
}
elseif( 1 == $vowel )
$word = substr_replace($word,$translate[“stressed”],$cur_pos,1); //
elseif( 2 == $vowel && 1 == $cur_vowel )
$word = substr_replace($word,$translate[“stressed”],$cur_pos,1); // предполагаем, что в двухсложных словах первый слог ударный
elseif( 3 <= $vowel && $cur_vowel == $vowel - 2 )
$word = substr_replace($word,$translate[“stressed”],$cur_pos,1); // предполагаем, что слог ударный предпредпоследний
else
$word = substr_replace($word,$translate[“sound”],$cur_pos,1);
$cur_pos++;
}
}
}
$sound = implode( $words, ' ' ); // клеим обратно
// согласные
foreach( array_filter($literal,
create_function('$item','if( $item[”status”] === “согласный”) return true; return false;'))
as $sign => $translate )
{
// готовим
$cur_pos = 0;
while( false !== $cur_pos = strpos($sound,$sign,$cur_pos) )
{
// print $cur_pos.' = '.$sound[$cur_pos].”<br />\r\n”;
if( sizeof($translate)==3 )
{
$x = array_pop(array_keys($translate)); // снимаем третий элемент
if( strpos( $x, $sound[$cur_pos+1] ) || $cur_pos === strlen($sound) )
{
$sound = substr_replace($sound,$translate[$x],$cur_pos,1);
} elseif ( $sound[$cur_pos] === $sound[$cur_pos+1] )
$sound = substr_replace($sound,$translate[“sound”],$cur_pos,2); // все двойные редуцируются
else
$sound = substr_replace($sound,$translate[“sound”],$cur_pos,1);
} else
{
$sound = substr_replace($sound,$translate[“sound”],$cur_pos,1);
}
$cur_pos++;
}
}
// алес. фонемы привели к одному виду
// дальше используем любой алгоритм для вычисления числового эквивалента
// но остаётся сомнение. очень хочется расстаться с глухими предлогами перед глухими согласными (”к скалам”)
$sound = preg_replace('~[,.\~`1234567890-=\~!@#$%^&*()_+|{}\]\];:\'”<>/? ]~','',$sound) ;
// print $sound;
// print str_to_translit($sound);
// print soundex(str_to_translit($sound));
$res = str_to_upper($source[0]).substr(soundex(str_to_translit($sound)),1);
return $res;
}
// (c) http://ru2.php.net/manual/en/function.strtoupper.php#74574
//Russian
function str_to_upper($str){
return strtr($str,
“abcdefghijklmnopqrstuvwxyz”.
“\xE0\xE1\xE2\xE3\xE4\xE5″.
“\xb8\xe6\xe7\xe8\xe9\xea”.
“\xeb\xeC\xeD\xeE\xeF\xf0″.
“\xf1\xf2\xf3\xf4\xf5\xf6″.
“\xf7\xf8\xf9\xfA\xfB\xfC”.
“\xfD\xfE\xfF”,
“ABCDEFGHIJKLMNOPQRSTUVWXYZ”.
“\xC0\xC1\xC2\xC3\xC4\xC5″.
“\xA8\xC6\xC7\xC8\xC9\xCA”.
“\xCB\xCC\xCD\xCE\xCF\xD0″.
“\xD1\xD2\xD3\xD4\xD5\xD6″.
“\xD7\xD8\xD9\xDA\xDB\xDC”.
“\xDD\xDE\xDF”);
}
function str_to_translit($str){
return strtr($str,
“abcdefghijklmnopqrstuvwxyz”.
“\xE0\xE1\xE2\xE3\xE4\xE5″.
“\xb8\xe6\xe7\xe8\xe9\xea”.
“\xeb\xeC\xeD\xeE\xeF\xf0″.
“\xf1\xf2\xf3\xf4\xf5\xf6″.
“\xf7\xf8\xf9\xfA\xfB\xfC”.
“\xfD\xfE\xfF”,
“abcdefghijklmnopqrstuvwxyz”.
“abvgde”.
“?*ziik”.
“lmnopr”.
“stufhc”.
“4ww\”y`”.
“eua”);
}
?>
upd: ps: хотелось бы отметить, что приведённый код служит, скорее, для иллюстрации алгоритма, чем для применения на практике. практическую реализацию можно сделать в другой форме
спасибо.
Комментариев нет
Комментариев нет.
Извините, комментирование на данный момент закрыто.