Skip to content

Commit

Permalink
Add run-away vowels list of Geographical names and fix some problems …
Browse files Browse the repository at this point in the history
…in geographical inflection
  • Loading branch information
wapmorgan committed Sep 7, 2018
1 parent b000f59 commit e78b738
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 52 deletions.
111 changes: 67 additions & 44 deletions src/Russian/GeographicalNamesInflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@ class GeographicalNamesInflection extends \morphos\BaseInflection implements Cas
'санкт',
];

protected static $runawayVowelsExceptions = [
'торжо*к',
'волоче*к',
'оре*л',
];

/**
* @return array|bool
*/
protected static function getRunAwayVowelsList()
{
$runawayVowelsNormalized = [];
foreach (self::$runawayVowelsExceptions as $word) {
$runawayVowelsNormalized[str_replace('*', null, $word)] = S::indexOf($word, '*') - 1;
}
return $runawayVowelsNormalized;
}

/**
* Проверяет, склоняемо ли название
* @param string $name Название
Expand Down Expand Up @@ -128,24 +146,24 @@ public static function getCases($name)
case 'ий':
$prefix = S::name(S::slice($name, 0, -2));
return [
self::IMENIT => $prefix . 'ий',
self::RODIT => $prefix . (self::isVelarConsonant(S::slice($name, -3, -2)) ? 'ого' : 'его'),
self::DAT => $prefix . (self::isVelarConsonant(S::slice($name, -3, -2)) ? 'ому' : 'ему'),
self::VINIT => $prefix . 'ий',
self::TVORIT => $prefix . 'им',
self::PREDLOJ => $prefix . (self::chooseEndingBySonority($prefix, 'ем', 'ом')),
self::IMENIT => $prefix.'ий',
self::RODIT => $prefix.(self::isVelarConsonant(S::slice($name, -3, -2)) ? 'ого' : 'его'),
self::DAT => $prefix.(self::isVelarConsonant(S::slice($name, -3, -2)) ? 'ому' : 'ему'),
self::VINIT => $prefix.'ий',
self::TVORIT => $prefix.'им',
self::PREDLOJ => $prefix.(self::chooseEndingBySonority($prefix, 'ем', 'ом')),
];

// Ростовская
case 'ая':
$prefix = S::name(S::slice($name, 0, -2));
return [
self::IMENIT => $prefix . 'ая',
self::RODIT => $prefix . 'ой',
self::DAT => $prefix . 'ой',
self::VINIT => $prefix . 'ую',
self::TVORIT => $prefix . 'ой',
self::PREDLOJ => $prefix . 'ой',
self::IMENIT => $prefix.'ая',
self::RODIT => $prefix.'ой',
self::DAT => $prefix.'ой',
self::VINIT => $prefix.'ую',
self::TVORIT => $prefix.'ой',
self::PREDLOJ => $prefix.'ой',
];

// Россошь
Expand All @@ -160,40 +178,39 @@ public static function getCases($name)
self::PREDLOJ => $prefix.'и',
];

// Орёл
case 'ел':
$prefix = S::name(S::slice($name, 0, -2));
return [
self::IMENIT => $prefix.'ёл',
self::RODIT => $prefix.'ла',
self::DAT => $prefix.'лу',
self::VINIT => $prefix.'ла',
self::TVORIT => $prefix.'лом',
self::PREDLOJ => $prefix.'ле',
];

// Грозный, Благодарный
case 'ый':
$prefix = S::name(S::slice($name, 0, -2));
return [
self::IMENIT => $prefix . 'ый',
self::RODIT => $prefix . 'ого',
self::DAT => $prefix . 'ому',
self::VINIT => $prefix . 'ый',
self::TVORIT => $prefix . 'ым',
self::PREDLOJ => $prefix . 'ом',
self::IMENIT => $prefix.'ый',
self::RODIT => $prefix.'ого',
self::DAT => $prefix.'ому',
self::VINIT => $prefix.'ый',
self::TVORIT => $prefix.'ым',
self::PREDLOJ => $prefix.'ом',
];

// Ставрополь, Ярославль, Электросталь
case 'ль':
$prefix = S::name(S::slice($name, 0, -1));

if ($name === 'электросталь')
return [
self::IMENIT => $prefix.'ь',
self::RODIT => $prefix.'и',
self::DAT => $prefix.'и',
self::VINIT => $prefix.'ь',
self::TVORIT => $prefix.'ью',
self::PREDLOJ => $prefix.'и',
];

return [
self::IMENIT => $prefix . 'ь',
self::RODIT => $prefix . 'я',
self::DAT => $prefix . 'ю',
self::VINIT => $prefix . 'ь',
self::TVORIT => $prefix . 'ем',
self::PREDLOJ => $prefix.(S::name(S::slice($name == 'электросталь', -1)) ? 'и' : 'е'),
self::IMENIT => $prefix.'ь',
self::RODIT => $prefix.'я',
self::DAT => $prefix.'ю',
self::VINIT => $prefix.'ь',
self::TVORIT => $prefix.'ем',
self::PREDLOJ => $prefix.'е',
];

// Тверь, Анадырь
Expand Down Expand Up @@ -294,7 +311,6 @@ public static function getCases($name)
];
}


switch (S::slice($name, -1)) {
case 'р':
// Бор
Expand All @@ -307,12 +323,13 @@ public static function getCases($name)
self::TVORIT => $prefix.'ром',
self::PREDLOJ => $prefix.'ру',
];

case 'ы':
// Чебоксары, Шахты
$prefix = S::name(S::slice($name, 0, -1));
return [
self::IMENIT => $prefix.'ы',
self::RODIT => $prefix.(self::isVelarConsonant(S::slice($name, -1, -1)) == ' '),
self::RODIT => $prefix,
self::DAT => $prefix.'ам',
self::VINIT => $prefix.'ы',
self::TVORIT => $prefix.'ами',
Expand Down Expand Up @@ -357,13 +374,22 @@ public static function getCases($name)
}

if (self::isConsonant(S::slice($name, -1)) && !in_array($name, self::$ovAbnormalExceptions, true)) {
$runaway_vowels_list = static::getRunAwayVowelsList();

// if run-away vowel in name
if (isset($runaway_vowels_list[$name])) {
$runaway_vowel_offset = $runaway_vowels_list[$name];
$prefix = S::name(S::slice($name, 0, $runaway_vowel_offset) . S::slice($name, $runaway_vowel_offset + 1));
} else {
$prefix = S::name($name);
}

// Париж, Валаам, Киев
$prefix = S::name($name);
return [
self::IMENIT => $prefix,
self::IMENIT => S::name($name),
self::RODIT => $prefix . 'а',
self::DAT => $prefix . 'у',
self::VINIT => $prefix,
self::VINIT => S::name($name),
self::TVORIT => $prefix . (self::isVelarConsonant(S::slice($name, -2, -1)) ? 'ем' : 'ом'),
self::PREDLOJ => $prefix . 'е',
];
Expand All @@ -375,9 +401,6 @@ public static function getCases($name)
// ово, ёво, ...
if (in_array(S::slice($name, -3, -1), $suffixes, true)) {
$prefix = S::name(S::slice($name, 0, -1));
return [
self::PREDLOJ => $prefix.'о',
];
}
// ов, её, ...
elseif (in_array(S::slice($name, -2), $suffixes, true)) {
Expand Down
12 changes: 4 additions & 8 deletions src/Russian/NounPluralization.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,16 @@ class NounPluralization extends \morphos\NounPluralization implements Cases
'глото*к',
];

protected static $runawayVowelsNormalized = false;

/**
* @return array|bool
*/
protected static function getRunAwayVowelsList()
{
if (self::$runawayVowelsNormalized === false) {
self::$runawayVowelsNormalized = [];
foreach (self::$runawayVowelsExceptions as $word) {
self::$runawayVowelsNormalized[str_replace('*', null, $word)] = S::indexOf($word, '*') - 1;
}
$runawayVowelsNormalized = [];
foreach (self::$runawayVowelsExceptions as $word) {
$runawayVowelsNormalized[str_replace('*', null, $word)] = S::indexOf($word, '*') - 1;
}
return self::$runawayVowelsNormalized;
return $runawayVowelsNormalized;
}

/**
Expand Down
8 changes: 8 additions & 0 deletions tests/Russian/GeographicalNamesInflectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ public function wordsProvider()
['Киров', 'Кирова', 'Кирову', 'Киров', 'Кировом', 'Кирове'],
['Керчь', 'Керчи', 'Керчи', 'Керчь', 'Керчью', 'Керчи'],
['Анадырь', 'Анадыря', 'Анадырю', 'Анадырь', 'Анадырем', 'Анадыре'],
['Россошь', 'Россоши', 'Россоши', 'Россошь', 'Россошью', 'Россоши'],
['Чебоксары', 'Чебоксар', 'Чебоксарам', 'Чебоксары', 'Чебоксарами', 'Чебоксарах'],

// с беглой гласной
['Торжок', 'Торжка', 'Торжку', 'Торжок', 'Торжком', 'Торжке'],
['Вышний Волочек', 'Вышнего Волочка', 'Вышнему Волочку', 'Вышний Волочек', 'Вышним Волочком', 'Вышнем Волочке'],
['Орел', 'Орла', 'Орлу', 'Орел', 'Орлом', 'Орле'],

// сложные названия
['Санкт-Петербург', 'Санкт-Петербурга', 'Санкт-Петербургу', 'Санкт-Петербург', 'Санкт-Петербургом', 'Санкт-Петербурге'],
Expand All @@ -72,6 +79,7 @@ public function wordsProvider()

// исключения
['Великие Луки', 'Великих Лук', 'Великим Лукам', 'Великие Луки', 'Великими Луками', 'Великих Луках'],
['Электросталь', 'Электростали', 'Электростали', 'Электросталь', 'Электросталью', 'Электростали'],

// неизменяемые названия
['США', 'США', 'США', 'США', 'США', 'США'],
Expand Down

0 comments on commit e78b738

Please sign in to comment.