├── .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 | 
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 |
--------------------------------------------------------------------------------