├── .gitmodules ├── LICENCE.md ├── Petrovich.php ├── README.md └── Trait └── Petrovich.php /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rules"] 2 | path = rules 3 | url = https://github.com/petrovich/petrovich-rules.git 4 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 2 | 3 | Grigory Parshikov 4 | MikeBazhenov 5 | 6 | MIT License 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining 9 | a copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /Petrovich.php: -------------------------------------------------------------------------------- 1 | rules = get_object_vars(json_decode($rules_array)); 36 | 37 | if (isset($gender) && $gender != Petrovich::GENDER_ANDROGYNOUS) 38 | $this->gender = $gender; 39 | } 40 | 41 | /** 42 | * Определяет пол по отчеству 43 | * @param $middlename 44 | * @return integer 45 | * @throws Exception 46 | */ 47 | public function detectGender($middlename) 48 | { 49 | if(empty($middlename)) 50 | throw new Exception('Middlename cannot be empty.'); 51 | 52 | switch ( mb_substr( mb_strtolower($middlename) , -4)) 53 | { 54 | case 'оглы': return Petrovich::GENDER_MALE; break; 55 | case 'кызы': return Petrovich::GENDER_FEMALE; break; 56 | } 57 | 58 | switch ( mb_substr( mb_strtolower($middlename) , -2)) 59 | { 60 | case 'ич': return Petrovich::GENDER_MALE; break; 61 | case 'на': return Petrovich::GENDER_FEMALE; break; 62 | default: return Petrovich::GENDER_ANDROGYNOUS; break; 63 | } 64 | } 65 | 66 | /** 67 | * Задаём имя и слоняем его 68 | * 69 | * @param $firstname 70 | * @param $case 71 | * @return bool|string 72 | * @throws Exception 73 | */ 74 | public function firstname($firstname, $case = Petrovich::CASE_NOMENATIVE) { 75 | if(empty($firstname)) 76 | throw new Exception('Firstname cannot be empty.'); 77 | 78 | if ($case === Petrovich::CASE_NOMENATIVE) { 79 | return $firstname; 80 | } 81 | 82 | return $this->inflect($firstname,$case,__FUNCTION__); 83 | } 84 | 85 | /** 86 | * Задём отчество и склоняем его 87 | * 88 | * @param $middlename 89 | * @param $case 90 | * @return bool|string 91 | * @throws Exception 92 | */ 93 | public function middlename($middlename, $case = Petrovich::CASE_NOMENATIVE) { 94 | if(empty($middlename)) 95 | throw new Exception('Middlename cannot be empty.'); 96 | 97 | if ($case === Petrovich::CASE_NOMENATIVE) { 98 | return $middlename; 99 | } 100 | 101 | return $this->inflect($middlename,$case,__FUNCTION__); 102 | } 103 | 104 | /** 105 | * Задаём фамилию и слоняем её 106 | * 107 | * @param $lastname 108 | * @param $case 109 | * @return bool|string 110 | * @throws Exception 111 | */ 112 | public function lastname($lastname, $case = Petrovich::CASE_NOMENATIVE) { 113 | if(empty($lastname)) 114 | throw new Exception('Lastname cannot be empty.'); 115 | 116 | if ($case === Petrovich::CASE_NOMENATIVE) { 117 | return $lastname; 118 | } 119 | 120 | return $this->inflect($lastname,$case,__FUNCTION__); 121 | } 122 | 123 | /** 124 | * Функция проверяет заданное имя,фамилию или отчество на исключение 125 | * и склоняет 126 | * 127 | * @param $name 128 | * @param $case 129 | * @param $type 130 | * @return bool|string 131 | */ 132 | private function inflect($name,$case,$type) { 133 | $names_arr = explode('-',$name); 134 | $result = array(); 135 | 136 | foreach($names_arr as $arr_name) { 137 | if(($exception = $this->checkException($arr_name,$case,$type)) !== false) { 138 | $result[] = $exception; 139 | } 140 | else { 141 | $result[] = $this->findInRules($arr_name,$case,$type); 142 | } 143 | } 144 | return implode('-',$result); 145 | } 146 | 147 | /** 148 | * Поиск в массиве правил 149 | * 150 | * @param $name 151 | * @param $case 152 | * @param $type 153 | * @return string 154 | */ 155 | private function findInRules($name,$case,$type) { 156 | foreach($this->rules[$type]->suffixes as $rule) { 157 | if ( ! $this->checkGender($rule->gender) ) 158 | continue; 159 | foreach($rule->test as $last_char) { 160 | $last_name_char = mb_substr($name,mb_strlen($name)-mb_strlen($last_char),mb_strlen($last_char)); 161 | if($last_char == $last_name_char) { 162 | if($rule->mods[$case] == '.') 163 | return $name; 164 | return $this->applyRule($rule->mods,$name,$case); 165 | } 166 | } 167 | } 168 | return $name; 169 | } 170 | 171 | /** 172 | * Проверка на совпадение в исключениях 173 | * 174 | * @param $name 175 | * @param $case 176 | * @param $type 177 | * @return bool|string 178 | */ 179 | private function checkException($name,$case,$type) { 180 | if(!isset($this->rules[$type]->exceptions)) 181 | return false; 182 | 183 | $lower_name = mb_strtolower($name); 184 | 185 | foreach($this->rules[$type]->exceptions as $rule) { 186 | if ( ! $this->checkGender($rule->gender) ) 187 | continue; 188 | if(array_search($lower_name,$rule->test) !== false) { 189 | if($rule->mods[$case] == '.') 190 | return $name; 191 | return $this->applyRule($rule->mods,$name,$case); 192 | } 193 | } 194 | return false; 195 | } 196 | 197 | /** 198 | * Склоняем заданное слово 199 | * 200 | * @param $mods 201 | * @param $name 202 | * @param $case 203 | * @return string 204 | */ 205 | private function applyRule($mods,$name,$case) { 206 | $result = mb_substr($name,0,mb_strlen($name) - mb_substr_count($mods[$case],'-')); 207 | $result .= str_replace('-','',$mods[$case]); 208 | return $result; 209 | } 210 | 211 | /** 212 | * Преобразует строковое обозначение пола в числовое 213 | * @param string 214 | * @return integer 215 | */ 216 | private function getGender($gender) { 217 | switch($gender) { 218 | case 'male': return Petrovich::GENDER_MALE; break; 219 | case 'female': return Petrovich::GENDER_FEMALE; break; 220 | case 'androgynous': return Petrovich::GENDER_ANDROGYNOUS; break; 221 | } 222 | } 223 | 224 | /** 225 | * Проверяет переданный пол на соответствие установленному 226 | * @param string 227 | * @return bool 228 | */ 229 | private function checkGender($gender) { 230 | return $this->gender === $this->getGender($gender) || $this->getGender($gender) === Petrovich::GENDER_ANDROGYNOUS; 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Petrovich](https://raw.github.com/rocsci/petrovich/master/petrovich.png) 2 | 3 | Склонение падежей русских имён, фамилий и отчеств. 4 | 5 | Портированная версия с [Ruby](https://github.com/petrovich/petrovich-ruby) на PHP 6 | 7 | Лицензия MIT 8 | 9 | ## Пример 10 | 11 | https://github.com/parshikov/petrovich-php-example 12 | 13 | ##Установка 14 | 15 | Для работы требуется PHP >= 5.3 16 | 17 | Загрузите файлы в папку с библиотеками на сервере. 18 | 19 | ```bash 20 | cd lib 21 | git clone https://github.com/petrovich/petrovich-php.git petrovich-php 22 | ``` 23 | 24 | если вы хотите использовать ```petrovich``` как submodule, 25 | 26 | ```bash 27 | git submodule add --init https://github.com/petrovich/petrovich-php.git lib/petrovich-php 28 | ``` 29 | 30 | или просто скачайте исходный код со страницы проекта на Github. 31 | 32 | ##Использование 33 | 34 | В библиотеку входит класс ```Petrovich``` и trait ```Trait_Petrovich``` 35 | 36 | ### Использование класса 37 | 38 | ```php 39 | mb_internal_encoding('UTF-8'); 40 | 41 | require_once('path-to-lib/petrovich-php/Petrovich.php'); 42 | 43 | $petrovich = new Petrovich(Petrovich::GENDER_MALE); 44 | 45 | $firstname = "Александр"; 46 | $middlename = "Сергеевич"; 47 | $lastname = "Пушкин"; 48 | 49 | echo $petrovich->detectGender("Петровна"); // Petrovich::GENDER_FEMALE (см. пункт Пол) 50 | 51 | echo '
Родительный падеж:
'; 52 | echo $petrovich->firstname($firstname, Petrovich::CASE_GENITIVE).'
'; // Александра 53 | echo $petrovich->middlename($middlename, Petrovich::CASE_GENITIVE).'
'; // Сергеевича 54 | echo $petrovich->lastname($lastname, Petrovich::CASE_GENITIVE).'
'; // Пушкина 55 | ``` 56 | 57 | ### Использование trait'а 58 | 59 | Trait содержит в себе 60 | * Свойства 61 | * ```firstname``` 62 | * ```middlename``` 63 | * ```lastname``` 64 | * ```gender``` 65 | * Методы 66 | * ```firstname($case)``` 67 | * ```middlename($case)``` 68 | * ```lastname($case)``` 69 | 70 | ```php 71 | mb_internal_encoding('UTF-8'); 72 | 73 | require_once('path-to-lib/petrovich-php/Petrovich.php'); 74 | require_once('path-to-lib/petrovich-php/Trait/Petrovich.php'); 75 | 76 | class User { 77 | use Trait_Petrovich; 78 | } 79 | 80 | $user = new User(); 81 | 82 | $user->lastname = "Пушкин"; 83 | $user->firstname = "Александр"; 84 | $user->middlename = "Сергеевич"; 85 | 86 | $user->firstname(Petrovich::CASE_GENITIVE); // Пушкина 87 | $user->lastname(Petrovich::CASE_GENITIVE); // Александра 88 | $user->middlename(Petrovich::CASE_GENITIVE); // Сергеевича 89 | ``` 90 | 91 | ## Падежи 92 | Названия суффиксов для методов образованы от английских названий соответствующих падежей. Полный список поддерживаемых падежей приведён в таблице ниже. 93 | 94 | | Суффикс метода | Падеж | Характеризующий вопрос | 95 | |----------------|--------------|------------------------| 96 | | CASE_NOMENATIVE| именительный | Кто? Что? | 97 | | CASE_GENITIVE | родительный | Кого? Чего? | 98 | | CASE_DATIVE | дательный | Кому? Чему? | 99 | | CASE_ACCUSATIVE| винительный | Кого? Что? | 100 | | CASE_INSTRUMENTAL | творительный | Кем? Чем? | 101 | | CASE_PREPOSITIONAL | предложный | О ком? О чём? | 102 | 103 | ## Пол 104 | Метод ```Petrovich::detectGender``` возвращает пол, на основе отчества. Возвращаемое значение не зависит от пола, переданного в конструктор. 105 | Для полов определены следующие константы 106 | * GENDER_ANDROGYNOUS - пол не определен; 107 | * GENDER_MALE - мужской пол; 108 | * GENDER_FEMALE - женский пол. 109 | -------------------------------------------------------------------------------- /Trait/Petrovich.php: -------------------------------------------------------------------------------- 1 | firstname; 23 | } 24 | 25 | if (!isset($this->petrovich)) 26 | $this->petrovich = new Petrovich($this->gender); 27 | 28 | return $this->petrovich->firstname($this->firstname,$case); 29 | } 30 | 31 | /** 32 | * Задём отчество и склоняем его 33 | * 34 | * @param $case 35 | * @return bool|string 36 | * @throws \ErrorException 37 | */ 38 | public function middlename($case = Petrovich::CASE_NOMENATIVE) { 39 | if ($case === Petrovich::CASE_NOMENATIVE) { 40 | return $this->middlename; 41 | } 42 | 43 | if (!isset($this->petrovich)) 44 | $this->petrovich = new Petrovich($this->gender); 45 | 46 | return $this->petrovich->middlename($this->middlename,$case); 47 | } 48 | 49 | /** 50 | * Задаём фамилию и слоняем её 51 | * 52 | * @param $case 53 | * @return bool|string 54 | * @throws \ErrorException 55 | */ 56 | public function lastname($case = Petrovich::CASE_NOMENATIVE) { 57 | if ($case === Petrovich::CASE_NOMENATIVE) { 58 | return $this->lastname; 59 | } 60 | 61 | if (!isset($this->petrovich)) 62 | $this->petrovich = new Petrovich($this->gender); 63 | 64 | return $this->petrovich->lastname($this->lastname,$case); 65 | } 66 | } 67 | --------------------------------------------------------------------------------