Skip to content

Commit

Permalink
Improve geo names inflection
Browse files Browse the repository at this point in the history
  • Loading branch information
wapmorgan committed Sep 20, 2017
1 parent dd63975 commit ff1acaf
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 8 deletions.
20 changes: 20 additions & 0 deletions src/BaseInflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,30 @@ abstract class BaseInflection implements Cases
public static function isMutable($name)
{
}

public static function getCases($name)
{
}

public static function getCase($name, $case)
{
}

/**
* Составляет один массив с падежами из нескольких массивов падежей разных слов
* @param array $words Двумерный массив слов и их падежей
* @param string $delimiter Разделитель между падежами слов
* @return array Одномерный массив падежей
*/
public static function composeCasesFromWords(array $words, $delimiter = ' ') {
$cases = [];
foreach (CasesHelper::getAllCases() as $case) {
$composed_case = [];
foreach ($words as $wordCases) {
$composed_case[] = $wordCases[$case];
}
$cases[$case] = implode($delimiter, $composed_case);
}
return $cases;
}
}
13 changes: 13 additions & 0 deletions src/CasesHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,17 @@ public static function canonizeCase($case)
throw new Exception('Invalid case: '.$case);
}
}

public static function getAllCases()
{
return [
Cases::NOMINATIVE,
Cases::GENITIVE,
Cases::GENETIVE,
Cases::DATIVE,
Cases::ACCUSATIVE,
Cases::ABLATIVE,
Cases::PREPOSITIONAL,
];
}
}
29 changes: 28 additions & 1 deletion src/Russian/GeographicalNamesInflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,25 @@ class GeographicalNamesInflection extends \morphos\BaseInflection implements Cas
public static function isMutable($name)
{
$name = S::lower($name);

// // ends with 'ы' or 'и': plural form
// if (in_array(S::slice($name, -1), array('и', 'ы')))
// return false;

if (in_array($name, self::$abbreviations)) {
return false;
}

// N край
if (S::slice($name, -5) == ' край') {
return static::isMutable(S::slice($name, 0, -5));
}

// город N
if (S::slice($name, 0, 6) == 'город ') {
return true;
}

// ends with 'е' or 'о', but not with 'ово/ёво/ево/ино/ыно'
if (in_array(S::slice($name, -1), array('е', 'о')) && !in_array(S::slice($name, -3, -1), array('ов', 'ёв', 'ев', 'ин', 'ын'))) {
return false;
Expand All @@ -37,6 +50,20 @@ public static function getCases($name)
{
$name = S::lower($name);

// N край
if (S::slice($name, -5) == ' край') {
return self::composeCasesFromWords([static::getCases(S::slice($name, 0, -5)), NounDeclension::getCases('край')]);

}

// город N
if (S::slice($name, 0, 6) == 'город ') {
return self::composeCasesFromWords([
NounDeclension::getCases('город'),
array_combine(self::getAllCases(), array_fill(0, 6, S::slice($name, -6)))
]);
}

// check for name of two words
if (strpos($name, ' ') !== false) {
$parts = explode(' ', $name);
Expand Down Expand Up @@ -69,7 +96,7 @@ public static function getCases($name)
self::DAT => $prefix.(self::isVelarConsonant(S::slice($name, -3, -2)) ? 'ому' : 'ему'),
self::VINIT => $prefix.'ий',
self::TVORIT => $prefix.'им',
self::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ем',
self::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.(self::chooseEndingBySonority($prefix, 'ем', 'ом')),
);
} else if (S::slice($name, -2) == 'ый') {
// Грозный, Благодарный
Expand Down
78 changes: 71 additions & 7 deletions src/Russian/RussianLanguage.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

trait RussianLanguage
{
/**
* @var array Все гласные
*/
public static $vowels = array(
'а',
'е',
Expand All @@ -19,6 +22,9 @@ trait RussianLanguage
'я',
);

/**
* @var array Все согласные
*/
public static $consonants = array(
'б',
'в',
Expand All @@ -43,6 +49,9 @@ trait RussianLanguage
'щ',
);

/**
* @var array Пары согласных
*/
public static $pairs = array(
'б' => 'п',
'в' => 'ф',
Expand All @@ -52,29 +61,50 @@ trait RussianLanguage
'з' => 'с',
);

public static $deafConsonants = ['х', 'ч', 'щ'];
public static $sonorousConsonants = ['л', 'м', 'н', 'р'];

/**
* @var array Звонкие согласные
*/
public static $sonorousConsonants = ['б', 'в', 'г', 'д', 'з', 'ж', 'л', 'м', 'н', 'р'];
/**
* @var array Глухие согласные
*/
public static $deafConsonants = ['п', 'ф', 'к', 'т', 'с', 'ш', 'х', 'ч', 'щ'];

/**
* Проверка гласной
*/
public static function isVowel($char)
{
return in_array($char, self::$vowels);
}

/**
* Проверка согласной
*/
public static function isConsonant($char)
{
return in_array($char, self::$consonants);
}

public static function isDeafConsonant($char)
/**
* Проверка звонкости согласной
*/
public static function isSonorousConsonant($char)
{
return in_array($char, self::$deafConsonants);
return in_array($char, self::$sonorousConsonants);
}

public static function isSonorousConsonant($char)
/**
* Проверка глухости согласной
*/
public static function isDeafConsonant($char)
{
return in_array($char, self::$sonorousConsonants);
return in_array($char, self::$deafConsonants);
}

/**
* Щипящая ли согласная
*/
public static function isHissingConsonant($consonant)
{
return in_array(S::lower($consonant), array('ж', 'ш', 'ч', 'щ'));
Expand All @@ -85,17 +115,26 @@ protected static function isVelarConsonant($consonant)
return in_array(S::lower($consonant), array('г', 'к', 'х'));
}

/**
* Подсчет слогов
*/
public static function countSyllables($string)
{
return S::chars_count($string, self::$vowels);
}

/**
* Проверка парности согласной
*/
public static function isPaired($consonant)
{
$consonant = S::lower($consonant);
return array_key_exists($consonant, self::$pairs) || (array_search($consonant, self::$pairs) !== false);
}

/**
* Проверка мягкости последней согласной
*/
public static function checkLastConsonantSoftness($word)
{
if (($substring = S::last_position_for_one_of_chars(S::lower($word), self::$consonants)) !== false) {
Expand All @@ -108,6 +147,9 @@ public static function checkLastConsonantSoftness($word)
return false;
}

/**
* Выбор предлога по первой букве
*/
public static function choosePrepositionByFirstLetter($word, $prepositionWithVowel, $preposition)
{
if (in_array(S::upper(S::slice($word, 0, 1)), array('А', 'О', 'И', 'У', 'Э'))) {
Expand All @@ -117,6 +159,9 @@ public static function choosePrepositionByFirstLetter($word, $prepositionWithVow
}
}

/**
* Выбор окончания в зависимости от мягкости
*/
public static function chooseVowelAfterConsonant($last, $soft_last, $after_soft, $after_hard)
{
if ((RussianLanguage::isHissingConsonant($last) && !in_array($last, array('ж', 'ч'))) || /*self::isVelarConsonant($last) ||*/ $soft_last) {
Expand Down Expand Up @@ -185,4 +230,23 @@ public static function about($word)

return 'о '.$word;
}

/**
* Выбирает первое или второе окончание в зависимости от звонкости/глухости в конце слова.
* @param string $word Слово (или префикс), на основе звонкости которого нужно выбрать окончание
* @param string $ifSonorous Окончание, если слово оканчивается на звонкую согласную
* @param string $ifDead Окончание, если слово оканчивается на глухую согласную
* @return string Первое или второе окончание
*/
public static function chooseEndingBySonority($word, $ifSononous, $ifDeaf)
{
$last = S::slice($word, -1);
var_dump($last);
if (self::isSonorousConsonant($last))
return $ifSononous;
if (self::isDeafConsonant($last))
return $ifDeaf;

throw new \Exception('Not implemented');
}
}

0 comments on commit ff1acaf

Please sign in to comment.