From e0572bdddaba85622d37728449caa12f6c961f48 Mon Sep 17 00:00:00 2001 From: wapmorgan Date: Fri, 3 Feb 2017 23:20:24 +0300 Subject: [PATCH] Add gender to cardinal numerals --- README.md | 8 ++- src/NumeralCreation.php | 4 ++ src/Russian/CardinalNumeral.php | 76 ++++++++++++++++++++------- tests/Russian/CardinalNumeralTest.php | 19 ++++--- 4 files changed, 79 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 80dba45..d5fe14e 100644 --- a/README.md +++ b/README.md @@ -349,8 +349,10 @@ echo $count.' '.Plurality::pluralize($word, $count, false); All number creation classes are similar and have two common methods: -- `string getForm($number, $case)` - Get one form of a number. -- `array getForms($number)` - Get all forms of a number. +- `string getForm($number, $case, $gender = NumeralCreation::MALE)` - Get one form of a number. +- `array getForms($number, $gender = NumeralCreation::MALE)` - Get all forms of a number. + +`$gender` is one of `morphos\NumeralCreation` constants: `MALE` or `FEMALE` or `NEUTER`. ### Cardinal numbers (`CardinalNumeral`) @@ -359,6 +361,7 @@ _Creation of cardinal numerals in russian language._ Create declension class object: ```php +use morphos\NumeralCreation; use morphos\Russian\CardinalNumeral; use morphos\Russian\Cases; @@ -371,6 +374,7 @@ Get text representation of a number: $number = 4351; $numeral = $cardinal->getForm($number, Cases::IMENIT); // четыре тысячи триста пятьдесят один +$numeral = $cardinal->getForm($number, Cases::IMENIT, NumeralCreation::FEMALE); // четыре тысячи триста пятьдесят одна ``` If you need all forms, you can get all forms of a name: diff --git a/src/NumeralCreation.php b/src/NumeralCreation.php index af276d4..079b0d4 100644 --- a/src/NumeralCreation.php +++ b/src/NumeralCreation.php @@ -2,6 +2,10 @@ namespace morphos; class NumeralCreation implements Cases { + const MALE = 'm'; + const FEMALE = 'f'; + const NEUTER = 'n'; + public function getForms($number) {} public function getForm($number, $case) {} } diff --git a/src/Russian/CardinalNumeral.php b/src/Russian/CardinalNumeral.php index 204dca6..696c095 100644 --- a/src/Russian/CardinalNumeral.php +++ b/src/Russian/CardinalNumeral.php @@ -59,20 +59,56 @@ class CardinalNumeral extends NumeralCreation implements Cases { protected $precalculated = array( 'один' => array( - self::IMENIT => 'один', - self::RODIT => 'одного', - self::DAT => 'одному', - self::VINIT => 'один', - self::TVORIT => 'одним', - self::PREDLOJ => 'об одном', + self::MALE => array( + self::IMENIT => 'один', + self::RODIT => 'одного', + self::DAT => 'одному', + self::VINIT => 'один', + self::TVORIT => 'одним', + self::PREDLOJ => 'об одном', + ), + self::FEMALE => array( + self::IMENIT => 'одна', + self::RODIT => 'одной', + self::DAT => 'одной', + self::VINIT => 'одну', + self::TVORIT => 'одной', + self::PREDLOJ => 'об одной', + ), + self::NEUTER => array( + self::IMENIT => 'одно', + self::RODIT => 'одного', + self::DAT => 'одному', + self::VINIT => 'одно', + self::TVORIT => 'одним', + self::PREDLOJ => 'об одном', + ), ), 'два' => array( - self::IMENIT => 'два', - self::RODIT => 'двух', - self::DAT => 'двум', - self::VINIT => 'два', - self::TVORIT => 'двумя', - self::PREDLOJ => 'о двух', + self::MALE => array( + self::IMENIT => 'два', + self::RODIT => 'двух', + self::DAT => 'двум', + self::VINIT => 'два', + self::TVORIT => 'двумя', + self::PREDLOJ => 'о двух', + ), + self::FEMALE => array( + self::IMENIT => 'две', + self::RODIT => 'двух', + self::DAT => 'двум', + self::VINIT => 'два', + self::TVORIT => 'двумя', + self::PREDLOJ => 'о двух', + ), + self::NEUTER => array( + self::IMENIT => 'два', + self::RODIT => 'двух', + self::DAT => 'двум', + self::VINIT => 'два', + self::TVORIT => 'двумя', + self::PREDLOJ => 'о двух', + ), ), 'три' => array( self::IMENIT => 'три', @@ -116,12 +152,16 @@ class CardinalNumeral extends NumeralCreation implements Cases { ), ); - public function getForms($number) { + public function getForms($number, $gender = self::MALE) { // simple numeral if (isset($this->words[$number]) || isset($this->exponents[$number])) { $word = isset($this->words[$number]) ? $this->words[$number] : $this->exponents[$number]; if (isset($this->precalculated[$word])) { - return $this->precalculated[$word]; + if (isset($this->precalculated[$word][self::MALE])) { + return $this->precalculated[$word][$gender]; + } else { + return $this->precalculated[$word]; + } } else if (($number >= 5 && $number <= 20) || $number == 30) { $prefix = slice($word, 0, -1); return array( @@ -182,7 +222,7 @@ public function getForms($number) { foreach (array_reverse($this->exponents, true) as $word_number => $word) { if ($number >= $word_number) { $count = floor($number / $word_number); - $parts[] = $this->getForms($count); + $parts[] = $this->getForms($count, ($word_number == 1000 ? self::FEMALE : self::MALE)); // get forms of word if (empty($this->declension)) $this->declension = new GeneralDeclension(); @@ -211,7 +251,7 @@ public function getForms($number) { foreach (array_reverse($this->words, true) as $word_number => $word) { if ($number >= $word_number) { - $parts[] = $this->getForms($word_number); + $parts[] = $this->getForms($word_number, $gender); $number %= $word_number; } } @@ -229,8 +269,8 @@ public function getForms($number) { } } - public function getForm($number, $form) { - $forms = $this->getForms($number); + public function getForm($number, $form, $gender = self::MALE) { + $forms = $this->getForms($number, $gender); return $forms[$form]; } } diff --git a/tests/Russian/CardinalNumeralTest.php b/tests/Russian/CardinalNumeralTest.php index d2cb718..ee3103f 100644 --- a/tests/Russian/CardinalNumeralTest.php +++ b/tests/Russian/CardinalNumeralTest.php @@ -2,6 +2,7 @@ namespace morphos\test\Russian; require __DIR__.'/../../vendor/autoload.php'; +use morphos\NumeralCreation; use morphos\Russian\Cases; use morphos\Russian\CardinalNumeral; @@ -15,7 +16,7 @@ public function setUp() { /** * @dataProvider numbersProvider */ - public function testGetForms($number, $case, $case2, $case3, $case4, $case5, $case6) { + public function testGetForms($number, $gender, $case, $case2, $case3, $case4, $case5, $case6) { $this->assertEquals(array( Cases::IMENIT => $case, Cases::RODIT => $case2, @@ -23,17 +24,19 @@ public function testGetForms($number, $case, $case2, $case3, $case4, $case5, $ca Cases::VINIT => $case4, Cases::TVORIT => $case5, Cases::PREDLOJ => $case6, - ), $this->cardinal->getForms($number)); + ), $this->cardinal->getForms($number, $gender)); } public function numbersProvider() { return array( - array(1, 'один', 'одного', 'одному', 'один', 'одним', 'об одном'), - array(201, 'двести один', 'двухсот одного', 'двумстам одному', 'двести один', 'двумястами одним', 'о двухстах одном'), - array(344, 'триста сорок четыре', 'трехсот сорока четырех', 'тремстам сорока четырем', 'триста сорок четыре', 'тремястами сорока четырьмя', 'о трехстах сорока четырех'), - array(3651, 'три тысячи шестьсот пятьдесят один', 'трех тысяч шестисот пятидесяти одного', 'трем тысячам шестистам пятидесяти одному', 'три тысячи шестьсот пятьдесят один', 'тремя тысячами шестьюстами пятьюдесятью одним', 'о трех тысячах шестистах пятидесяти одном'), - array(9999, 'девять тысяч девятьсот девяносто девять', 'девяти тысяч девятисот девяноста девяти', 'девяти тысячам девятистам девяноста девяти', 'девять тысяч девятьсот девяносто девять', 'девятью тысячами девятьюстами девяноста девятью', 'о девяти тысячах девятистах девяноста девяти'), - array(1234567890, + array(1, NumeralCreation::MALE, 'один', 'одного', 'одному', 'один', 'одним', 'об одном'), + array(1, NumeralCreation::FEMALE, 'одна', 'одной', 'одной', 'одну', 'одной', 'об одной'), + array(201, NumeralCreation::MALE, 'двести один', 'двухсот одного', 'двумстам одному', 'двести один', 'двумястами одним', 'о двухстах одном'), + array(344, NumeralCreation::MALE, 'триста сорок четыре', 'трехсот сорока четырех', 'тремстам сорока четырем', 'триста сорок четыре', 'тремястами сорока четырьмя', 'о трехстах сорока четырех'), + array(1007, NumeralCreation::MALE, 'одна тысяча семь', 'одной тысячи семи', 'одной тысяче семи', 'одну тысячу семь', 'одной тысячей семью', 'об одной тысяче семи'), + array(3651, NumeralCreation::MALE, 'три тысячи шестьсот пятьдесят один', 'трех тысяч шестисот пятидесяти одного', 'трем тысячам шестистам пятидесяти одному', 'три тысячи шестьсот пятьдесят один', 'тремя тысячами шестьюстами пятьюдесятью одним', 'о трех тысячах шестистах пятидесяти одном'), + array(9999, NumeralCreation::MALE, 'девять тысяч девятьсот девяносто девять', 'девяти тысяч девятисот девяноста девяти', 'девяти тысячам девятистам девяноста девяти', 'девять тысяч девятьсот девяносто девять', 'девятью тысячами девятьюстами девяноста девятью', 'о девяти тысячах девятистах девяноста девяти'), + array(1234567890, NumeralCreation::MALE, 'один миллиард двести тридцать четыре миллиона пятьсот шестьдесят семь тысяч восемьсот девяносто', 'одного миллиарда двухсот тридцати четырех миллионов пятисот шестидесяти семи тысяч восьмисот девяноста', 'одному миллиарду двумстам тридцати четырем миллионам пятистам шестидесяти семи тысячам восьмистам девяноста',