<?php
class phpMorphy_TextTools_Grammems {
protected
$all_grammems,
$essential_grammems,
$essential_grammems_with_gender;
function __construct() {
$this->all_grammems = $this->getAllGrammems();
$this->essential_grammems = $this->getEssentialGrammems();
$this->essential_grammems_with_gender =
array_merge($this->essential_grammems, $this->getGenderGrammems());
}
protected function flatizeArray($ary) {
return call_user_func_array('array_merge', $ary);
}
protected function getAllGrammems() {
return array(
// род
array('МР', 'ЖР', 'СР'),
// одушевленность, неодушевленность
array('ОД', 'НО'),
// число
array('ЕД', 'МН'),
// падеж
array('ИМ', 'РД', 'ДТ', 'ВН', 'ТВ', 'ПР', 'ЗВ',
'2'),
// действительный, страдательный залог
array('ДСТ', 'СТР'),
// время
array('НСТ', 'ПРШ', 'БУД'),
// повелительная форма глагола
array('ПВЛ'),
// лицо
array('1Л', '2Л', '3Л'),
// краткость
array('КР'),
// сравнительная форма
array('СРАВН'),
// превосходная степень
array('ПРЕВ')
);
}
protected function getEssentialGrammems() {
$r = $this->getAllGrammems();
unset($r[0]); // род
unset($r[1]); // одушевленность, неодушевленность
// граммемы по которым происходит сопоставление
return $this->flatizeArray($r);
}
protected function getGenderGrammems() {
list($result) = $this->getAllGrammems();
return $result;
}
function normalizeGrammems($grammems, $withGender) {
return array_values(
array_intersect(
$grammems,
$withGender ? $this->essential_grammems_with_gender :
$this->essential_grammems
)
);
}
function stripGrammems($grammems, $exclude) {
return array_diff($grammems, $exclude);
}
function isEqualGrammems($a, $b) {
return count($a) == count($b) && count(array_diff($a, $b)) == 0;
}
function findGrammemsGroup($grammem) {
foreach($this->all_grammems as $group) {
if(in_array($grammem, $group)) {
return $group;
}
}
return false;
}
}
class phpMorphy_TextTools {
protected
$morphy,
$grammems
;
function __construct(phpMorphy $morphy) {
$this->morphy = $morphy;
$this->grammems = $this->createGrammems();
}
protected function createGrammems() {
return new phpMorphy_TextTools_Grammems();
}
protected function isCheckGenderForPartOfSpeech($pos) {
// для существительных род не проверяем
return $pos != 'С';
}
function changeFormByPattern($original, $replacement, $strict = true) {
$result_forms = array();
// ищем слово в словаре, получаем коллекцию парадигм, в которые входит
слово
if(false === ($collection = $this->morphy->findWord($original))) {
throw new Exception("Can`t find $original word");
}
// ищем в словаре слово на которве бедкм менять
if(false === ($collection_repl = $this->morphy->findWord($replacement)))
{
throw new Exception("Can`t find $replacement word");
}
// омонимия на уровне разных частей речи - ключ, лук, душа, стали и
т.п.
foreach($collection as $descriptor) {
// омонимия внутри форм одного слова
// стол имеет одинаковые формы для именительного и винительного
падежей
foreach($descriptor->getFoundWordForm() as $form) {
// запоминаем граммемы и часть речи для $original
$part_of_speech = $form->getPartOfSpeech();
$with_gender =
$this->isCheckGenderForPartOfSpeech($part_of_speech);
$grammems =
$this->grammems->normalizeGrammems($form->getGrammems(), $with_gender);
//var_dump($form->getWord(), $grammems);
// ищем форму в $collection_repl c этими характеристиками
// Ищем в коллекции по части речи
foreach($collection_repl->getByPartOfSpeech($part_of_speech) as
$descriptor_repl) {
$forms_repl = count($grammems) ?
$descriptor_repl->getWordFormsByGrammems($grammems) : $descriptor_repl;
foreach($forms_repl as $form_repl) {
if($form_repl->getPartOfSpeech() == $part_of_speech) {
// ВСЕ граммемы для каждой найденной формы должны
совпадать с $grammems (если $strict === true)
$repl_grammems =
$this->grammems->normalizeGrammems($form_repl->getGrammems(), $with_gender);
if(
$form_repl->getPartOfSpeech() == $part_of_speech
&&
(!$strict ||
$this->grammems->isEqualGrammems($repl_grammems, $grammems))
) {
// ОК, нашли форму
$result_forms[$form_repl->getWord()] = 1;
}
}
}
}
}
}
return array_keys($result_forms);
}
protected function stripInGroupGrammems($all, $user) {
foreach($user as $grammem) {
if(false !== ($group =
$this->grammems->findGrammemsGroup($grammem))) {
$all = $this->grammems->stripGrammems($all, $group);
}
}
return $all;
}
/*
function changeFormByGrammems($original, $grammems) {
if(false === ($collection = $this->morphy->findWord($original))) {
throw new Exception("Can`t find $original word");
}
$result = array();
$grammems = (array)$grammems;
foreach($collection as $descriptor) {
foreach($descriptor->getFoundWordForm() as $found_form) {
$stripped_grammems =
$this->stripInGroupGrammems($found_form->getGrammems(), $grammems);
$new_grammems = array_merge($stripped_grammems, $grammems);
foreach($descriptor->getWordFormsByGrammems($new_grammems) as
$form) {
$result[$form->getWord()] = 1;
}
}
}
return array_keys($result);
}
*/
function changeFormByGrammems($original, $grammems) {
if(false === ($collection = $this->morphy->findWord($original))) {
throw new Exception("Can`t find $original word");
}
$result = array();
$grammems = (array)$grammems;
foreach($collection as $descriptor) {
foreach($descriptor->getFoundWordForm() as $found_form) {
foreach($descriptor->getWordFormsByGrammems($grammems) as $form)
{
if($form->getPartOfSpeech() ==
$found_form->getPartOfSpeech()) {
$result[$form->getWord()] = 1;
}
}
}
}
return array_keys($result);
}
}
$tools = new phpMorphy_TextTools($morphy);
$words = array(
'ДИВАНАМИ' => 'КРОВАТЬ',
'СТУЛОМ' => 'КРЕСЛО',
'ХОРОШИЙ' => 'ПЛОХОЙ',
'ПОЛУЧШЕ' => 'ПЛОХОЙ',
'НАИЛУЧШИЕ' => 'ПЛОХОЙ',
'ХОРОША' => 'ПЛОХОЙ',
'ДУША' => 'СТАЛЬ',
'БИЛИ' => 'ГЛАДИТЬ',
'БЬЮЩИЙ' => 'ПИТЬ',
'ТОРЧКОМ' => 'СТОЙМЯ',
'ДВАДЦАТЬЮ' => 'ТРИДЦАТЬ',
'А' => 'НО',
);
foreach($words as $from_word => $to_word) {
$result = $tools->changeFormByPattern($from_word, $to_word);
echo $from_word, ": ", implode(', ', $result), "\n";
}
var_dump($tools->changeFormByGrammems('ХОЖУ', array('МН', 'ПРШ')));
?>