- return: true - если было использовано правило из списка, false - если правило не было найденым
- access: protected
diff --git a/Docs/default/NCLNameCaseUa.html b/Docs/default/NCLNameCaseUa.html
index d1664e5..b482794 100644
--- a/Docs/default/NCLNameCaseUa.html
+++ b/Docs/default/NCLNameCaseUa.html
@@ -31,7 +31,7 @@
- индексы мужского и женского пола
- индексы всех падежей
Located in /NCL.NameCase.ua.php (line 17)
diff --git a/Docs/default/NCLNameCaseWord.html b/Docs/default/NCLNameCaseWord.html
index 090a056..ca13c6c 100644
--- a/Docs/default/NCLNameCaseWord.html
+++ b/Docs/default/NCLNameCaseWord.html
@@ -24,7 +24,7 @@
NCLNameCaseWord - класс, который служит для хранения всей информации о каждом слове
Located in /NCL/NCLNameCaseWord.php (line 8)
diff --git a/Docs/default/NCLStr.html b/Docs/default/NCLStr.html
index 6362ce9..559f49d 100644
--- a/Docs/default/NCLStr.html
+++ b/Docs/default/NCLStr.html
@@ -25,7 +25,7 @@
Класс содержит функции для работы со строками, которые используются в NCLNameCaseLib
Located in /NCL/NCLStr.php (line 8)
diff --git a/Docs/default/_NCL.NameCase.ua.php.html b/Docs/default/_NCL.NameCase.ua.php.html
index 9bac925..619111a 100644
--- a/Docs/default/_NCL.NameCase.ua.php.html
+++ b/Docs/default/_NCL.NameCase.ua.php.html
@@ -76,7 +76,7 @@
Украинские правила склонений ФИО. Правила определения пола человека по ФИО для украинского языка Система разделения фамилий имен и отчеств для украинского языка
diff --git a/Docs/elementindex.html b/Docs/elementindex.html
index 8868fec..3e46bea 100644
--- a/Docs/elementindex.html
+++ b/Docs/elementindex.html
@@ -440,14 +440,14 @@
-
-
Функция пытается применить цыпочку правил для мужских имен
+ Функция пытается применить цепочку правил для мужских имен
-
manFirstName
-
-
Функция пытается применить цыпочку правил для мужских имен
+ Функция пытается применить цепочку правил для мужских имен
-
manFirstName
@@ -552,14 +552,14 @@
-
-
Функция пытается применить цыпочку правил для мужских фамилий
+ Функция пытается применить цепочку правил для мужских фамилий
-
manSecondName
-
-
Функция пытается применить цыпочку правил для мужских фамилий
+ Функция пытается применить цепочку правил для мужских фамилий
-
manSecondName
@@ -1051,14 +1051,14 @@
-
-
Функция пытается применить цыпочку правил для женских имен
+ Функция пытается применить цепочку правил для женских имен
-
womanFirstName
-
-
Функция пытается применить цыпочку правил для женских имен
+ Функция пытается применить цепочку правил для женских имен
-
womanRule1
@@ -1114,7 +1114,7 @@
-
-
Функция пытается применить цыпочку правил для женских фамилий
+ Функция пытается применить цепочку правил для женских фамилий
-
womanSecondName
@@ -1128,7 +1128,7 @@
-
-
Функция пытается применить цыпочку правил для женских фамилий
+ Функция пытается применить цепочку правил для женских фамилий
-
wordForms
diff --git a/Docs/elementindex_NameCaseLib.html b/Docs/elementindex_NameCaseLib.html
index 915249c..549564b 100644
--- a/Docs/elementindex_NameCaseLib.html
+++ b/Docs/elementindex_NameCaseLib.html
@@ -452,14 +452,14 @@
-
-
Функция пытается применить цыпочку правил для мужских имен
+ Функция пытается применить цепочку правил для мужских имен
-
manFirstName
-
-
Функция пытается применить цыпочку правил для мужских имен
+ Функция пытается применить цепочку правил для мужских имен
-
manFirstName
@@ -564,14 +564,14 @@
-
-
Функция пытается применить цыпочку правил для мужских фамилий
+ Функция пытается применить цепочку правил для мужских фамилий
-
manSecondName
-
-
Функция пытается применить цыпочку правил для мужских фамилий
+ Функция пытается применить цепочку правил для мужских фамилий
-
manSecondName
@@ -1063,14 +1063,14 @@
-
-
Функция пытается применить цыпочку правил для женских имен
+ Функция пытается применить цепочку правил для женских имен
-
womanFirstName
-
-
Функция пытается применить цыпочку правил для женских имен
+ Функция пытается применить цепочку правил для женских имен
-
womanRule1
@@ -1126,7 +1126,7 @@
-
-
Функция пытается применить цыпочку правил для женских фамилий
+ Функция пытается применить цепочку правил для женских фамилий
-
womanSecondName
@@ -1140,7 +1140,7 @@
-
-
Функция пытается применить цыпочку правил для женских фамилий
+ Функция пытается применить цепочку правил для женских фамилий
-
wordForms
diff --git a/Docs/elementindex_default.html b/Docs/elementindex_default.html
index 00eccf5..3246e1e 100644
--- a/Docs/elementindex_default.html
+++ b/Docs/elementindex_default.html
@@ -432,7 +432,7 @@
-
-
Функция пытается применить цыпочку правил для мужских имен
+ Функция пытается применить цепочку правил для мужских имен
-
manRule1
@@ -530,7 +530,7 @@
-
-
Функция пытается применить цыпочку правил для мужских фамилий
+ Функция пытается применить цепочку правил для мужских фамилий
-
manSecondName
@@ -1118,7 +1118,7 @@
-
-
Функция пытается применить цыпочку правил для женских имен
+ Функция пытается применить цепочку правил для женских имен
-
womanRule1
@@ -1181,7 +1181,7 @@
-
-
Функция пытается применить цыпочку правил для женских фамилий
+ Функция пытается применить цепочку правил для женских фамилий
-
wordForms
diff --git a/Library/NCL/NCL.php b/Library/NCL/NCL.php
index 604830d..a8a0d2f 100644
--- a/Library/NCL/NCL.php
+++ b/Library/NCL/NCL.php
@@ -10,7 +10,7 @@
* - индексы всех падежей
*
* @author Андрей Чайка
- * @version 0.4
+ * @version 0.4.1
* @package NameCaseLib
*/
class NCL
diff --git a/Library/NCL/NCLNameCaseCore.php b/Library/NCL/NCLNameCaseCore.php
index a87a48c..43af4f3 100644
--- a/Library/NCL/NCLNameCaseCore.php
+++ b/Library/NCL/NCLNameCaseCore.php
@@ -5,11 +5,11 @@
* @package NameCaseLib
*/
/**
- *
+ *
*/
if (!defined('NCL_DIR'))
{
- define('NCL_DIR', dirname(__FILE__));
+ define('NCL_DIR', dirname(__FILE__));
}
require_once NCL_DIR . '/NCL.php';
@@ -18,1112 +18,1196 @@ require_once NCL_DIR . '/NCLNameCaseWord.php';
/**
* NCL NameCase Core
- *
+ *
* Набор основных функций, который позволяют сделать интерфейс слонения русского и украниского языка
* абсолютно одинаковым. Содержит все функции для внешнего взаимодействия с библиотекой.
- *
+ *
* @author Андрей Чайка
- * @version 0.4
+ * @version 0.4.1
* @package NameCaseLib
*/
class NCLNameCaseCore extends NCL
{
- /**
- * Версия библиотеки
- * @var string
- */
- protected $version = '0.4';
-
- /**
- * Версия языкового файла
- * @var string
- */
- protected $languageBuild = '0';
-
- /**
- * Готовность системы:
- * - Все слова идентифицированы (известо к какой части ФИО относится слово)
- * - У всех слов определен пол
- * Если все сделано стоит флаг true, при добавлении нового слова флаг сбрасывается на false
- * @var bool
- */
- private $ready = false;
- /**
- * Если все текущие слова было просклонены и в каждом слове уже есть результат склонения,
- * тогда true. Если было добавлено новое слово флаг збрасывается на false
- * @var bool
- */
- private $finished = false;
- /**
- * Массив содержит елементы типа NCLNameCaseWord. Это все слова которые нужно обработать и просклонять
- * @var array
- */
- private $words = array();
- /**
- * Переменная, в которую заносится слово с которым сейчас идет работа
- * @var string
- */
- protected $workingWord = '';
- /**
- * Метод Last() вырезает подстроки разной длины. Посколько одинаковых вызовов бывает несколько,
- * то все результаты выполнения кешируются в этом массиве.
- * @var array
- */
- protected $workindLastCache = array();
- /**
- * Номер последнего использованого правила, устанавливается методом Rule()
- * @var int
- */
- private $lastRule = 0;
- /**
- * Массив содержит результат склонения слова - слово во всех падежах
- * @var array
- */
- protected $lastResult = array();
- /**
- * Массив содержит информацию о том какие слова из массива $this->words относятся к
- * фамилии, какие к отчеству а какие к имени. Массив нужен потому, что при добавлении слов мы не
- * всегда знаем какая часть ФИО сейчас, поэтому после идентификации всех слов генерируется массив
- * индексов для быстрого поиска в дальнейшем.
- * @var array
- */
- private $index = array();
-
- /**
- * Метод очищает результаты последнего склонения слова. Нужен при склонении нескольких слов.
- */
- private function reset()
- {
- $this->lastRule = 0;
- $this->lastResult = array();
- }
-
- /**
- * Сбрасывает все информацию на начальную. Очищает все слова добавленые в систему.
- * После выполнения система готова работать с начала.
- * @return NCLNameCaseCore
- */
- public function fullReset()
- {
- $this->words = array();
- $this->index = array('N' => array(), 'F' => array(), 'S' => array());
- $this->reset();
- $this->notReady();
- return $this;
- }
-
- /**
- * Устанавливает флаги о том, что система не готово и слова еще не были просклонены
- */
- private function notReady()
- {
- $this->ready = false;
- $this->finished = false;
- }
-
- /**
- * Устанавливает номер последнего правила
- * @param int $index номер правила которое нужно установить
- */
- protected function Rule($index)
- {
- $this->lastRule = $index;
- }
-
- /**
- * Устанавливает слово текущим для работы системы. Очищает кеш слова.
- * @param string $word слово, которое нужно установить
- */
- protected function setWorkingWord($word)
- {
- //Сбрасываем настройки
- $this->reset();
- //Ставим слово
- $this->workingWord = $word;
- //Чистим кеш
- $this->workindLastCache = array();
- }
-
- /**
- * Если $stopAfter = 0, тогда вырезает $length последних букв с текущего слова ($this->workingWord)
- * Если нет, тогда вырезает $stopAfter букв начиная от $length с конца
- * @param int $length количество букв с конца
- * @param int $stopAfter количество букв которые нужно вырезать (0 - все)
- * @return string требуемая подстрока
- */
- protected function Last($length=1, $stopAfter=0)
- {
- //Сколько букв нужно вырезать все или только часть
- if (!$stopAfter)
- {
- $cut = $length;
- }
- else
- {
- $cut = $stopAfter;
- }
-
- //Проверяем кеш
- if (!isset($this->workindLastCache[$length][$stopAfter]))
- {
- $this->workindLastCache[$length][$stopAfter] = NCLStr::substr($this->workingWord, -$length, $cut);
- }
- return $this->workindLastCache[$length][$stopAfter];
- }
-
- /**
- * Над текущим словом ($this->workingWord) выполняются правила в порядке указаном в $rulesArray.
- * $gender служит для указания какие правила использовать мужские ('man') или женские ('woman')
- * @param string $gender - префикс мужских/женских правил
- * @param array $rulesArray - массив, порядок выполнения правил
- * @return boolean если правило было задествовано, тогда true, если нет - тогда false
- */
- protected function RulesChain($gender, $rulesArray)
- {
- foreach ($rulesArray as $ruleID)
- {
- $ruleMethod = $gender . 'Rule' . $ruleID;
- if ($this->$ruleMethod())
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Если $string строка, тогда проверяется входит ли буква $letter в строку $string
- * Если $string массив, тогда проверяется входит ли строка $letter в массив $string
- * @param string $letter буква или строка, которую нужно искать
- * @param mixed $string строка или массив, в котором нужно искать
- * @return bool true если искомое значение найдено
- */
- protected function in($letter, $string)
- {
- //Если второй параметр массив
- if (is_array($string))
- {
- return in_array($letter, $string);
- }
- else
- {
- if (!$letter or NCLStr::strpos($string, $letter) === false)
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- }
-
- /**
- * Функция проверяет, входит ли имя $nameNeedle в перечень имен $names.
- * @param string $nameNeedle - имя которое нужно найти
- * @param array $names - перечень имен в котором нужно найти имя
- */
- protected function inNames($nameNeedle, $names)
- {
- if (!is_array($names))
- {
- $names = array($names);
- }
-
- foreach ($names as $name)
- {
- if (NCLStr::strtolower($nameNeedle) == NCLStr::strtolower($name))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Склоняет слово $word, удаляя из него $replaceLast последних букв
- * и добавляя в каждый падеж окончание из массива $endings.
- * @param string $word слово, к которому нужно добавить окончания
- * @param array $endings массив окончаний
- * @param int $replaceLast сколько последних букв нужно убрать с начального слова
- */
- protected function wordForms($word, $endings, $replaceLast=0)
- {
- //Создаем массив с именительный падежом
- $result = array($this->workingWord);
- //Убираем в окончание лишние буквы
- $word = NCLStr::substr($word, 0, NCLStr::strlen($word) - $replaceLast);
-
- //Добавляем окончания
- for ($padegIndex = 1; $padegIndex < $this->CaseCount; $padegIndex++)
- {
- $result[$padegIndex] = $word . $endings[$padegIndex - 1];
- }
-
- $this->lastResult = $result;
- }
-
- /**
- * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
- * со словом $firstname и пометкой, что это имя
- * @param string $firstname имя
- * @return NCLNameCaseCore
- */
- public function setFirstName($firstname="")
- {
- if ($firstname)
- {
- $index = count($this->words);
- $this->words[$index] = new NCLNameCaseWord($firstname);
- $this->words[$index]->setNamePart('N');
- $this->notReady();
- }
- return $this;
- }
-
- /**
- * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
- * со словом $secondname и пометкой, что это фамилия
- * @param string $secondname фамилия
- * @return NCLNameCaseCore
- */
- public function setSecondName($secondname="")
- {
- if ($secondname)
- {
- $index = count($this->words);
- $this->words[$index] = new NCLNameCaseWord($secondname);
- $this->words[$index]->setNamePart('S');
- $this->notReady();
- }
- return $this;
- }
-
- /**
- * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
- * со словом $fathername и пометкой, что это отчество
- * @param string $fathername отчество
- * @return NCLNameCaseCore
- */
- public function setFatherName($fathername="")
- {
- if ($fathername)
- {
- $index = count($this->words);
- $this->words[$index] = new NCLNameCaseWord($fathername);
- $this->words[$index]->setNamePart('F');
- $this->notReady();
- }
- return $this;
- }
-
- /**
- * Всем словам устанавливается пол, который может иметь следующие значения
- * - 0 - не определено
- * - NCL::$MAN - мужчина
- * - NCL::$WOMAN - женщина
- * @param int $gender пол, который нужно установить
- * @return NCLNameCaseCore
- */
- public function setGender($gender=0)
- {
- foreach ($this->words as $word)
- {
- $word->setTrueGender($gender);
- }
- return $this;
- }
-
- /**
- * В система заносится сразу фамилия, имя, отчество
- * @param string $secondName фамилия
- * @param string $firstName имя
- * @param string $fatherName отчество
- * @return NCLNameCaseCore
- */
- public function setFullName($secondName="", $firstName="", $fatherName="")
- {
- $this->setFirstName($firstName);
- $this->setSecondName($secondName);
- $this->setFatherName($fatherName);
- return $this;
- }
-
- /**
- * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
- * со словом $firstname и пометкой, что это имя
- * @param string $firstname имя
- * @return NCLNameCaseCore
- */
- public function setName($firstname="")
- {
- return $this->setFirstName($firstname);
- }
-
- /**
- * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
- * со словом $secondname и пометкой, что это фамилия
- * @param string $secondname фамилия
- * @return NCLNameCaseCore
- */
- public function setLastName($secondname="")
- {
- return $this->setSecondName($secondname);
- }
-
- /**
- * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
- * со словом $secondname и пометкой, что это фамилия
- * @param string $secondname фамилия
- * @return NCLNameCaseCore
- */
- public function setSirName($secondname="")
- {
- return $this->setSecondName($secondname);
- }
-
- /**
- * Если слово $word не идентифицировано, тогда определяется это имя, фамилия или отчество
- * @param NCLNameCaseWord $word слово которое нужно идентифицировать
- */
- private function prepareNamePart(NCLNameCaseWord $word)
- {
- if (!$word->getNamePart())
- {
- $this->detectNamePart($word);
- }
- }
-
- /**
- * Проверяет все ли слова идентифицированы, если нет тогда для каждого определяется это имя, фамилия или отчество
- */
- private function prepareAllNameParts()
- {
- foreach ($this->words as $word)
- {
- $this->prepareNamePart($word);
- }
- }
-
- /**
- * Определяет пол для слова $word
- * @param NCLNameCaseWord $word слово для которого нужно определить пол
- */
- private function prepareGender(NCLNameCaseWord $word)
- {
- if (!$word->isGenderSolved())
- {
- $namePart = $word->getNamePart();
- switch ($namePart)
- {
- case 'N': $this->GenderByFirstName($word);
- break;
- case 'F': $this->GenderByFatherName($word);
- break;
- case 'S': $this->GenderBySecondName($word);
- break;
- }
- }
- }
-
- /**
- * Для всех слов проверяет определен ли пол, если нет - определяет его
- * После этого расчитывает пол для всех слов и устанавливает такой пол всем словам
- * @return bool был ли определен пол
- */
- private function solveGender()
- {
- //Ищем, может гдето пол уже установлен
- foreach ($this->words as $word)
- {
- if ($word->isGenderSolved())
- {
- $this->setGender($word->gender());
- return true;
- }
- }
-
- //Если нет тогда определяем у каждого слова и потом сумируем
- $man = 0;
- $woman = 0;
-
- foreach ($this->words as $word)
- {
- $this->prepareGender($word);
- $gender = $word->getGender();
- $man+=$gender[NCL::$MAN];
- $woman+=$gender[NCL::$WOMAN];
- }
-
- if ($man > $woman)
- {
- $this->setGender(NCL::$MAN);
- }
- else
- {
- $this->setGender(NCL::$WOMAN);
- }
-
- return true;
- }
-
- /**
- * Генерируется массив, который содержит информацию о том какие слова из массива $this->words относятся к
- * фамилии, какие к отчеству а какие к имени. Массив нужен потому, что при добавлении слов мы не
- * всегда знаем какая часть ФИО сейчас, поэтому после идентификации всех слов генерируется массив
- * индексов для быстрого поиска в дальнейшем.
- */
- private function generateIndex()
- {
- $this->index = array('N' => array(), 'S' => array(), 'F' => array());
- foreach ($this->words as $index => $word)
- {
- $namepart = $word->getNamePart();
- $this->index[$namepart][] = $index;
- }
- }
-
- /**
- * Выполнет все необходимые подготовления для склонения.
- * Все слова идентфицируются. Определяется пол.
- * Обновляется индекс.
- */
- private function prepareEverything()
- {
- if (!$this->ready)
- {
- $this->prepareAllNameParts();
- $this->solveGender();
- $this->generateIndex();
- $this->ready = true;
- }
- }
-
- /**
- * По указаным словам определяется пол человека:
- * - 0 - не определено
- * - NCL::$MAN - мужчина
- * - NCL::$WOMAN - женщина
- * @return int текущий пол человека
- */
- public function genderAutoDetect()
- {
- $this->prepareEverything();
- if (isset($this->words[0]))
- {
- return $this->words[0]->gender();
- }
- return false;
- }
-
- /**
- * Разбивает строку $fullname на слова и возвращает формат в котором записано имя
- * Формат:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @param string $fullname строка, для которой необходимо определить формат
- * @return array формат в котором записано имя массив типа $this->words
- */
- private function splitFullName($fullname)
- {
-
- $fullname = trim($fullname);
- $list = explode(' ', $fullname);
-
- foreach ($list as $word)
- {
- $this->words[] = new NCLNameCaseWord($word);
- }
-
- $this->prepareEverything();
- $formatArr = array();
-
- foreach ($this->words as $word)
- {
- $formatArr[] = $word->getNamePart();
- }
-
- return $this->words;
- }
-
- /**
- * Разбивает строку $fullname на слова и возвращает формат в котором записано имя
- * Формат:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @param string $fullname строка, для которой необходимо определить формат
- * @return string формат в котором записано имя
- */
- public function getFullNameFormat($fullname)
- {
- $this->fullReset();
- $words = $this->splitFullName($fullname);
- $format = '';
- foreach ($words as $word)
- {
- $format .= $word->getNamePart() . ' ';
- }
- return $format;
- }
-
- /**
- * Склоняет слово $word по нужным правилам в зависимости от пола и типа слова
- * @param NCLNameCaseWord $word слово, которое нужно просклонять
- */
- private function WordCase(NCLNameCaseWord $word)
- {
- $gender = ($word->gender() == NCL::$MAN ? 'man' : 'woman');
-
- $namepart = '';
-
- switch ($word->getNamePart())
- {
- case 'F': $namepart = 'Father';
- break;
- case 'N': $namepart = 'First';
- break;
- case 'S': $namepart = 'Second';
- break;
- }
-
- $method = $gender . $namepart . 'Name';
-
- $this->setWorkingWord($word->getWord());
-
- if ($this->$method())
- {
- $word->setNameCases($this->lastResult);
- $word->setRule($this->lastRule);
- }
- else
- {
- $word->setNameCases(array_fill(0, $this->CaseCount, $word->getWord()));
- $word->setRule(-1);
- }
- }
-
- /**
- * Производит склонение всех слов, который хранятся в массиве $this->words
- */
- private function AllWordCases()
- {
- if (!$this->finished)
- {
- $this->prepareEverything();
-
- foreach ($this->words as $word)
- {
- $this->WordCase($word);
- }
-
- $this->finished = true;
- }
- }
-
- /**
- * Если указан номер падежа $number, тогда возвращается строка с таким номером падежа,
- * если нет, тогда возвращается массив со всеми падежами текущего слова.
- * @param NCLNameCaseWord $word слово для котрого нужно вернуть падеж
- * @param int $number номер падежа, который нужно вернуть
- * @return mixed массив или строка с нужным падежом
- */
- private function getWordCase(NCLNameCaseWord $word, $number=null)
- {
- $cases = $word->getNameCases();
- if (is_null($number) or $number < 0 or $number > ($this->CaseCount - 1))
- {
- return $cases;
- }
- else
- {
- return $cases[$number];
- }
- }
-
- /**
- * Если нужно было просклонять несколько слов, то их необходимо собрать в одну строку.
- * Эта функция собирает все слова указаные в $indexArray в одну строку.
- * @param array $indexArray индексы слов, которые необходимо собрать вместе
- * @param int $number номер падежа
- * @return mixed либо массив со всеми падежами, либо строка с одним падежом
- */
- private function getCasesConnected($indexArray, $number=null)
- {
- $readyArr = array();
- foreach ($indexArray as $index)
- {
- $readyArr[] = $this->getWordCase($this->words[$index], $number);
- }
-
- $all = count($readyArr);
- if ($all)
- {
- if (is_array($readyArr[0]))
- {
- //Масив нужно скелить каждый падеж
- $resultArr = array();
- for ($case = 0; $case < $this->CaseCount; $case++)
- {
- $tmp = array();
- for ($i = 0; $i < $all; $i++)
- {
- $tmp[] = $readyArr[$i][$case];
- }
- $resultArr[$case] = implode(' ', $tmp);
- }
- return $resultArr;
- }
- else
- {
- return implode(' ', $readyArr);
- }
- }
- return '';
- }
-
- /**
- * Функция ставит имя в нужный падеж.
- *
- * Если указан номер падежа $number, тогда возвращается строка с таким номером падежа,
- * если нет, тогда возвращается массив со всеми падежами текущего слова.
- * @param int $number номер падежа
- * @return mixed массив или строка с нужным падежом
- */
- public function getFirstNameCase($number=null)
- {
- $this->AllWordCases();
-
- return $this->getCasesConnected($this->index['N'], $number);
- }
-
- /**
- * Функция ставит фамилию в нужный падеж.
- *
- * Если указан номер падежа $number, тогда возвращается строка с таким номером падежа,
- * если нет, тогда возвращается массив со всеми падежами текущего слова.
- * @param int $number номер падежа
- * @return mixed массив или строка с нужным падежом
- */
- public function getSecondNameCase($number=null)
- {
- $this->AllWordCases();
-
- return $this->getCasesConnected($this->index['S'], $number);
- }
-
- /**
- * Функция ставит отчество в нужный падеж.
- *
- * Если указан номер падежа $number, тогда возвращается строка с таким номером падежа,
- * если нет, тогда возвращается массив со всеми падежами текущего слова.
- * @param int $number номер падежа
- * @return mixed массив или строка с нужным падежом
- */
- public function getFatherNameCase($number=null)
- {
- $this->AllWordCases();
-
- return $this->getCasesConnected($this->index['F'], $number);
- }
-
- /**
- * Функция ставит имя $firstName в нужный падеж $CaseNumber по правилам пола $gender.
- *
- * Если указан номер падежа $CaseNumber, тогда возвращается строка с таким номером падежа,
- * если нет, тогда возвращается массив со всеми падежами текущего слова.
- * @param string $firstName имя, которое нужно просклонять
- * @param int $CaseNumber номер падежа
- * @param int $gender пол, который нужно использовать
- * @return mixed массив или строка с нужным падежом
- */
- public function qFirstName($firstName, $CaseNumber=null, $gender=0)
- {
- $this->fullReset();
- $this->setFirstName($firstName);
- if ($gender)
- {
- $this->setGender($gender);
- }
- return $this->getFirstNameCase($CaseNumber);
- }
-
- /**
- * Функция ставит фамилию $secondName в нужный падеж $CaseNumber по правилам пола $gender.
- *
- * Если указан номер падежа $CaseNumber, тогда возвращается строка с таким номером падежа,
- * если нет, тогда возвращается массив со всеми падежами текущего слова.
- * @param string $secondName фамилия, которую нужно просклонять
- * @param int $CaseNumber номер падежа
- * @param int $gender пол, который нужно использовать
- * @return mixed массив или строка с нужным падежом
- */
- public function qSecondName($secondName, $CaseNumber=null, $gender=0)
- {
- $this->fullReset();
- $this->setSecondName($secondName);
- if ($gender)
- {
- $this->setGender($gender);
- }
-
- return $this->getSecondNameCase($CaseNumber);
- }
-
- /**
- * Функция ставит отчество $fatherName в нужный падеж $CaseNumber по правилам пола $gender.
- *
- * Если указан номер падежа $CaseNumber, тогда возвращается строка с таким номером падежа,
- * если нет, тогда возвращается массив со всеми падежами текущего слова.
- * @param string $fatherName отчество, которое нужно просклонять
- * @param int $CaseNumber номер падежа
- * @param int $gender пол, который нужно использовать
- * @return mixed массив или строка с нужным падежом
- */
- public function qFatherName($fatherName, $CaseNumber=null, $gender=0)
- {
- $this->fullReset();
- $this->setFatherName($fatherName);
- if ($gender)
- {
- $this->setGender($gender);
- }
- return $this->getFatherNameCase($CaseNumber);
- }
-
- /**
- * Склоняет текущие слова во все падежи и форматирует слово по шаблону $format
- * Формат:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @param string $format строка формат
- * @return array массив со всеми падежами
- */
- public function getFormattedArray($format)
- {
- if (is_array($format))
- {
- return $this->getFormattedArrayHard($format);
- }
-
- $length = NCLStr::strlen($format);
- $result = array();
- $cases = array();
- $cases['S'] = $this->getCasesConnected($this->index['S']);
- $cases['N'] = $this->getCasesConnected($this->index['N']);
- $cases['F'] = $this->getCasesConnected($this->index['F']);
-
- for ($curCase = 0; $curCase < $this->CaseCount; $curCase++)
- {
- $line = "";
- for ($i = 0; $i < $length; $i++)
- {
- $symbol = NCLStr::substr($format, $i, 1);
- if ($symbol == 'S')
- {
- $line.=$cases['S'][$curCase];
- }
- elseif ($symbol == 'N')
- {
- $line.=$cases['N'][$curCase];
- }
- elseif ($symbol == 'F')
- {
- $line.=$cases['F'][$curCase];
- }
- else
- {
- $line.=$symbol;
- }
- }
- $result[] = $line;
- }
- return $result;
- }
-
- /**
- * Склоняет текущие слова во все падежи и форматирует слово по шаблону $format
- * Формат:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @param array $format массив с форматом
- * @return array массив со всеми падежами
- */
- public function getFormattedArrayHard($format)
- {
-
- $result = array();
- $cases = array();
- foreach ($format as $word)
- {
- $cases[] = $word->getNameCases();
- }
-
- for ($curCase = 0; $curCase < $this->CaseCount; $curCase++)
- {
- $line = "";
- foreach ($cases as $value)
- {
- $line.=$value[$curCase] . ' ';
- }
- $result[] = trim($line);
- }
- return $result;
- }
-
- /**
- * Склоняет текущие слова в падеж $caseNum и форматирует слово по шаблону $format
- * Формат:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @param array $format массив с форматом
- * @return string строка в нужном падеже
- */
- public function getFormattedHard($caseNum=0, $format=array())
- {
- $result = "";
- foreach ($format as $word)
- {
- $cases = $word->getNameCases();
- $result.= $cases[$caseNum] . ' ';
- }
- return trim($result);
- }
-
- /**
- * Склоняет текущие слова в падеж $caseNum и форматирует слово по шаблону $format
- * Формат:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @param string $format строка с форматом
- * @return string строка в нужном падеже
- */
- public function getFormatted($caseNum=0, $format="S N F")
- {
- $this->AllWordCases();
- //Если не указан падеж используем другую функцию
- if (is_null($caseNum) or !$caseNum)
- {
- return $this->getFormattedArray($format);
- }
- //Если формат сложный
- elseif (is_array($format))
- {
- return $this->getFormattedHard($caseNum, $format);
- }
- else
- {
- $length = NCLStr::strlen($format);
- $result = "";
- for ($i = 0; $i < $length; $i++)
- {
- $symbol = NCLStr::substr($format, $i, 1);
- if ($symbol == 'S')
- {
- $result.=$this->getSecondNameCase($caseNum);
- }
- elseif ($symbol == 'N')
- {
- $result.=$this->getFirstNameCase($caseNum);
- }
- elseif ($symbol == 'F')
- {
- $result.=$this->getFatherNameCase($caseNum);
- }
- else
- {
- $result.=$symbol;
- }
- }
- return $result;
- }
- }
-
- /**
- * Склоняет фамилию $secondName, имя $firstName, отчество $fatherName
- * в падеж $caseNum по правилам пола $gender и форматирует результат по шаблону $format
- * Формат:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @param string $secondName фамилия
- * @param string $firstName имя
- * @param string $fatherName отчество
- * @param int $gender пол
- * @param int $caseNum номер падежа
- * @param string $format формат
- * @return mixed либо массив со всеми падежами, либо строка
- */
- public function qFullName($secondName="", $firstName="", $fatherName="", $gender=0, $caseNum=0, $format="S N F")
- {
- $this->fullReset();
- $this->setFirstName($firstName);
- $this->setSecondName($secondName);
- $this->setFatherName($fatherName);
- if ($gender)
- {
- $this->setGender($gender);
- }
-
- return $this->getFormatted($caseNum, $format);
- }
-
- /**
- * Склоняет ФИО $fullname в падеж $caseNum по правилам пола $gender.
- * Возвращает результат в таком же формате, как он и был.
- * @param string $fullname ФИО
- * @param int $caseNum номер падежа
- * @param int $gender пол человека
- * @return mixed либо массив со всеми падежами, либо строка
- */
- public function q($fullname, $caseNum=null, $gender=null)
- {
- $this->fullReset();
- $format = $this->splitFullName($fullname);
- if ($gender)
- {
- $this->setGender($gender);
- }
-
- return $this->getFormatted($caseNum, $format);
- }
-
- /**
- * Определяет пол человека по ФИО
- * @param string $fullname ФИО
- * @return int пол человека
- */
- public function genderDetect($fullname)
- {
- $this->fullReset();
- $this->splitFullName($fullname);
- return $this->genderAutoDetect();
- }
-
- /**
- * Возвращает внутренний массив $this->words каждая запись имеет тип NCLNameCaseWord
- * @return array Массив всех слов в системе
- */
- public function getWordsArray()
- {
- return $this->words;
- }
-
- /**
- * Функция пытается применить цыпочку правил для мужских имен
- * @return boolean true - если было использовано правило из списка, false - если правило не было найденым
- */
- protected function manFirstName()
- {
- return false;
- }
-
- /**
- * Функция пытается применить цыпочку правил для женских имен
- * @return boolean true - если было использовано правило из списка, false - если правило не было найденым
- */
- protected function womanFirstName()
- {
- return false;
- }
-
- /**
- * Функция пытается применить цыпочку правил для мужских фамилий
- * @return boolean true - если было использовано правило из списка, false - если правило не было найденым
- */
- protected function manSecondName()
- {
- return false;
- }
-
- /**
- * Функция пытается применить цыпочку правил для женских фамилий
- * @return boolean true - если было использовано правило из списка, false - если правило не было найденым
- */
- protected function womanSecondName()
- {
- return false;
- }
-
- /**
- * Функция склоняет мужский отчества
- * @return boolean true - если слово было успешно изменено, false - если не получилось этого сделать
- */
- protected function manFatherName()
- {
- return false;
- }
-
- /**
- * Функция склоняет женские отчества
- * @return boolean true - если слово было успешно изменено, false - если не получилось этого сделать
- */
- protected function womanFatherName()
- {
- return false;
- }
-
- /**
- * Определение пола по правилам имен
- * @param NCLNameCaseWord $word обьект класса слов, для которого нужно определить пол
- */
- protected function GenderByFirstName(NCLNameCaseWord $word)
- {
-
- }
-
- /**
- * Определение пола по правилам фамилий
- * @param NCLNameCaseWord $word обьект класса слов, для которого нужно определить пол
- */
- protected function GenderBySecondName(NCLNameCaseWord $word)
- {
-
- }
-
- /**
- * Определение пола по правилам отчеств
- * @param NCLNameCaseWord $word обьект класса слов, для которого нужно определить пол
- */
- protected function GenderByFatherName(NCLNameCaseWord $word)
- {
-
- }
-
- /**
- * Идетифицирует слово определяе имя это, или фамилия, или отчество
- * - N - имя
- * - S - фамилия
- * - F - отчество
- * @param NCLNameCaseWord $word обьект класса слов, который необходимо идентифицировать
- */
- protected function detectNamePart(NCLNameCaseWord $word)
- {
-
- }
-
- /**
- * Возвращает версию библиотеки
- * @return string версия библиотеки
- */
- public function version()
- {
- return $this->version;
- }
-
- /**
- * Возвращает версию использованого языкового файла
- * @return string версия языкового файла
- */
- public function languageVersion()
- {
- return $this->languageBuild;
- }
+
+ /**
+ * Версия библиотеки
+ * @var string
+ */
+ protected $version = '0.4.1';
+ /**
+ * Версия языкового файла
+ * @var string
+ */
+ protected $languageBuild = '0';
+ /**
+ * Готовность системы:
+ * - Все слова идентифицированы (известо к какой части ФИО относится слово)
+ * - У всех слов определен пол
+ * Если все сделано стоит флаг true, при добавлении нового слова флаг сбрасывается на false
+ * @var bool
+ */
+ private $ready = false;
+ /**
+ * Если все текущие слова было просклонены и в каждом слове уже есть результат склонения,
+ * тогда true. Если было добавлено новое слово флаг збрасывается на false
+ * @var bool
+ */
+ private $finished = false;
+ /**
+ * Массив содержит елементы типа NCLNameCaseWord. Это все слова которые нужно обработать и просклонять
+ * @var array
+ */
+ private $words = array();
+ /**
+ * Переменная, в которую заносится слово с которым сейчас идет работа
+ * @var string
+ */
+ protected $workingWord = '';
+ /**
+ * Метод Last() вырезает подстроки разной длины. Посколько одинаковых вызовов бывает несколько,
+ * то все результаты выполнения кешируются в этом массиве.
+ * @var array
+ */
+ protected $workindLastCache = array();
+ /**
+ * Номер последнего использованого правила, устанавливается методом Rule()
+ * @var int
+ */
+ private $lastRule = 0;
+ /**
+ * Массив содержит результат склонения слова - слово во всех падежах
+ * @var array
+ */
+ protected $lastResult = array();
+ /**
+ * Массив содержит информацию о том какие слова из массива $this->words относятся к
+ * фамилии, какие к отчеству а какие к имени. Массив нужен потому, что при добавлении слов мы не
+ * всегда знаем какая часть ФИО сейчас, поэтому после идентификации всех слов генерируется массив
+ * индексов для быстрого поиска в дальнейшем.
+ * @var array
+ */
+ private $index = array();
+
+ public $gender_koef=0;//вероятность автоопредления пола [0..10]. Достаточно точно при 0.1
+
+ /**
+ * Метод очищает результаты последнего склонения слова. Нужен при склонении нескольких слов.
+ */
+ private function reset()
+ {
+ $this->lastRule = 0;
+ $this->lastResult = array();
+ }
+
+ /**
+ * Сбрасывает все информацию на начальную. Очищает все слова добавленые в систему.
+ * После выполнения система готова работать с начала.
+ * @return NCLNameCaseCore
+ */
+ public function fullReset()
+ {
+ $this->words = array();
+ $this->index = array('N' => array(), 'F' => array(), 'S' => array());
+ $this->reset();
+ $this->notReady();
+ return $this;
+ }
+
+ /**
+ * Устанавливает флаги о том, что система не готово и слова еще не были просклонены
+ */
+ private function notReady()
+ {
+ $this->ready = false;
+ $this->finished = false;
+ }
+
+ /**
+ * Устанавливает номер последнего правила
+ * @param int $index номер правила которое нужно установить
+ */
+ protected function Rule($index)
+ {
+ $this->lastRule = $index;
+ }
+
+ /**
+ * Устанавливает слово текущим для работы системы. Очищает кеш слова.
+ * @param string $word слово, которое нужно установить
+ */
+ protected function setWorkingWord($word)
+ {
+ //Сбрасываем настройки
+ $this->reset();
+ //Ставим слово
+ $this->workingWord = $word;
+ //Чистим кеш
+ $this->workindLastCache = array();
+ }
+
+ /**
+ * Если не нужно склонять слово, делает результат таким же как и именительный падеж
+ */
+ protected function makeResultTheSame()
+ {
+ $this->lastResult = array_fill(0, $this->CaseCount, $this->workingWord);
+ }
+
+ /**
+ * Если $stopAfter = 0, тогда вырезает $length последних букв с текущего слова ($this->workingWord)
+ * Если нет, тогда вырезает $stopAfter букв начиная от $length с конца
+ * @param int $length количество букв с конца
+ * @param int $stopAfter количество букв которые нужно вырезать (0 - все)
+ * @return string требуемая подстрока
+ */
+ protected function Last($length=1, $stopAfter=0)
+ {
+ //Сколько букв нужно вырезать все или только часть
+ if (!$stopAfter)
+ {
+ $cut = $length;
+ }
+ else
+ {
+ $cut = $stopAfter;
+ }
+
+ //Проверяем кеш
+ if (!isset($this->workindLastCache[$length][$stopAfter]))
+ {
+ $this->workindLastCache[$length][$stopAfter] = NCLStr::substr($this->workingWord, -$length, $cut);
+ }
+ return $this->workindLastCache[$length][$stopAfter];
+ }
+
+ /**
+ * Над текущим словом ($this->workingWord) выполняются правила в порядке указаном в $rulesArray.
+ * $gender служит для указания какие правила использовать мужские ('man') или женские ('woman')
+ * @param string $gender - префикс мужских/женских правил
+ * @param array $rulesArray - массив, порядок выполнения правил
+ * @return boolean если правило было задествовано, тогда true, если нет - тогда false
+ */
+ protected function RulesChain($gender, $rulesArray)
+ {
+ foreach ($rulesArray as $ruleID)
+ {
+ $ruleMethod = $gender . 'Rule' . $ruleID;
+ if ($this->$ruleMethod())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Если $string строка, тогда проверяется входит ли буква $letter в строку $string
+ * Если $string массив, тогда проверяется входит ли строка $letter в массив $string
+ * @param string $letter буква или строка, которую нужно искать
+ * @param mixed $string строка или массив, в котором нужно искать
+ * @return bool true если искомое значение найдено
+ */
+ protected function in($letter, $string)
+ {
+ //Если второй параметр массив
+ if (is_array($string))
+ {
+ return in_array($letter, $string);
+ }
+ else
+ {
+ if (!$letter or NCLStr::strpos($string, $letter) === false)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Функция проверяет, входит ли имя $nameNeedle в перечень имен $names.
+ * @param string $nameNeedle - имя которое нужно найти
+ * @param array $names - перечень имен в котором нужно найти имя
+ */
+ protected function inNames($nameNeedle, $names)
+ {
+ if (!is_array($names))
+ {
+ $names = array($names);
+ }
+
+ foreach ($names as $name)
+ {
+ if (NCLStr::strtolower($nameNeedle) == NCLStr::strtolower($name))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Склоняет слово $word, удаляя из него $replaceLast последних букв
+ * и добавляя в каждый падеж окончание из массива $endings.
+ * @param string $word слово, к которому нужно добавить окончания
+ * @param array $endings массив окончаний
+ * @param int $replaceLast сколько последних букв нужно убрать с начального слова
+ */
+ protected function wordForms($word, $endings, $replaceLast=0)
+ {
+ //Создаем массив с именительный падежом
+ $result = array($this->workingWord);
+ //Убираем в окончание лишние буквы
+ $word = NCLStr::substr($word, 0, NCLStr::strlen($word) - $replaceLast);
+
+ //Добавляем окончания
+ for ($padegIndex = 1; $padegIndex < $this->CaseCount; $padegIndex++)
+ {
+ $result[$padegIndex] = $word . $endings[$padegIndex - 1];
+ }
+
+ $this->lastResult = $result;
+ }
+
+ /**
+ * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
+ * со словом $firstname и пометкой, что это имя
+ * @param string $firstname имя
+ * @return NCLNameCaseCore
+ */
+ public function setFirstName($firstname="")
+ {
+ if ($firstname)
+ {
+ $index = count($this->words);
+ $this->words[$index] = new NCLNameCaseWord($firstname);
+ $this->words[$index]->setNamePart('N');
+ $this->notReady();
+ }
+ return $this;
+ }
+
+ /**
+ * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
+ * со словом $secondname и пометкой, что это фамилия
+ * @param string $secondname фамилия
+ * @return NCLNameCaseCore
+ */
+ public function setSecondName($secondname="")
+ {
+ if ($secondname)
+ {
+ $index = count($this->words);
+ $this->words[$index] = new NCLNameCaseWord($secondname);
+ $this->words[$index]->setNamePart('S');
+ $this->notReady();
+ }
+ return $this;
+ }
+
+ /**
+ * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
+ * со словом $fathername и пометкой, что это отчество
+ * @param string $fathername отчество
+ * @return NCLNameCaseCore
+ */
+ public function setFatherName($fathername="")
+ {
+ if ($fathername)
+ {
+ $index = count($this->words);
+ $this->words[$index] = new NCLNameCaseWord($fathername);
+ $this->words[$index]->setNamePart('F');
+ $this->notReady();
+ }
+ return $this;
+ }
+
+ /**
+ * Всем словам устанавливается пол, который может иметь следующие значения
+ * - 0 - не определено
+ * - NCL::$MAN - мужчина
+ * - NCL::$WOMAN - женщина
+ * @param int $gender пол, который нужно установить
+ * @return NCLNameCaseCore
+ */
+ public function setGender($gender=0)
+ {
+ foreach ($this->words as $word)
+ {
+ $word->setTrueGender($gender);
+ }
+ return $this;
+ }
+
+ /**
+ * В система заносится сразу фамилия, имя, отчество
+ * @param string $secondName фамилия
+ * @param string $firstName имя
+ * @param string $fatherName отчество
+ * @return NCLNameCaseCore
+ */
+ public function setFullName($secondName="", $firstName="", $fatherName="")
+ {
+ $this->setFirstName($firstName);
+ $this->setSecondName($secondName);
+ $this->setFatherName($fatherName);
+ return $this;
+ }
+
+ /**
+ * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
+ * со словом $firstname и пометкой, что это имя
+ * @param string $firstname имя
+ * @return NCLNameCaseCore
+ */
+ public function setName($firstname="")
+ {
+ return $this->setFirstName($firstname);
+ }
+
+ /**
+ * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
+ * со словом $secondname и пометкой, что это фамилия
+ * @param string $secondname фамилия
+ * @return NCLNameCaseCore
+ */
+ public function setLastName($secondname="")
+ {
+ return $this->setSecondName($secondname);
+ }
+
+ /**
+ * В массив $this->words добавляется новый об’єкт класса NCLNameCaseWord
+ * со словом $secondname и пометкой, что это фамилия
+ * @param string $secondname фамилия
+ * @return NCLNameCaseCore
+ */
+ public function setSirName($secondname="")
+ {
+ return $this->setSecondName($secondname);
+ }
+
+ /**
+ * Если слово $word не идентифицировано, тогда определяется это имя, фамилия или отчество
+ * @param NCLNameCaseWord $word слово которое нужно идентифицировать
+ */
+ private function prepareNamePart(NCLNameCaseWord $word)
+ {
+ if (!$word->getNamePart())
+ {
+ $this->detectNamePart($word);
+ }
+ }
+
+ /**
+ * Проверяет все ли слова идентифицированы, если нет тогда для каждого определяется это имя, фамилия или отчество
+ */
+ private function prepareAllNameParts()
+ {
+ foreach ($this->words as $word)
+ {
+ $this->prepareNamePart($word);
+ }
+ }
+
+ /**
+ * Определяет пол для слова $word
+ * @param NCLNameCaseWord $word слово для которого нужно определить пол
+ */
+ private function prepareGender(NCLNameCaseWord $word)
+ {
+ if (!$word->isGenderSolved())
+ {
+ $namePart = $word->getNamePart();
+ switch ($namePart)
+ {
+ case 'N': $this->GenderByFirstName($word);
+ break;
+ case 'F': $this->GenderByFatherName($word);
+ break;
+ case 'S': $this->GenderBySecondName($word);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Для всех слов проверяет определен ли пол, если нет - определяет его
+ * После этого расчитывает пол для всех слов и устанавливает такой пол всем словам
+ * @return bool был ли определен пол
+ */
+ private function solveGender()
+ {
+ //Ищем, может гдето пол уже установлен
+ foreach ($this->words as $word)
+ {
+ if ($word->isGenderSolved())
+ {
+ $this->setGender($word->gender());
+ return true;
+ }
+ }
+
+ //Если нет тогда определяем у каждого слова и потом сумируем
+ $man = 0;
+ $woman = 0;
+
+ foreach ($this->words as $word)
+ {
+ $this->prepareGender($word);
+ $gender = $word->getGender();
+ $man+=$gender[NCL::$MAN];
+ $woman+=$gender[NCL::$WOMAN];
+ }
+
+ if ($man > $woman)
+ {
+ $this->setGender(NCL::$MAN);
+ }
+ else
+ {
+ $this->setGender(NCL::$WOMAN);
+ }
+
+ return true;
+ }
+
+ /**
+ * Генерируется массив, который содержит информацию о том какие слова из массива $this->words относятся к
+ * фамилии, какие к отчеству а какие к имени. Массив нужен потому, что при добавлении слов мы не
+ * всегда знаем какая часть ФИО сейчас, поэтому после идентификации всех слов генерируется массив
+ * индексов для быстрого поиска в дальнейшем.
+ */
+ private function generateIndex()
+ {
+ $this->index = array('N' => array(), 'S' => array(), 'F' => array());
+ foreach ($this->words as $index => $word)
+ {
+ $namepart = $word->getNamePart();
+ $this->index[$namepart][] = $index;
+ }
+ }
+
+ /**
+ * Выполнет все необходимые подготовления для склонения.
+ * Все слова идентфицируются. Определяется пол.
+ * Обновляется индекс.
+ */
+ private function prepareEverything()
+ {
+ if (!$this->ready)
+ {
+ $this->prepareAllNameParts();
+ $this->solveGender();
+ $this->generateIndex();
+ $this->ready = true;
+ }
+ }
+
+ /**
+ * По указаным словам определяется пол человека:
+ * - 0 - не определено
+ * - NCL::$MAN - мужчина
+ * - NCL::$WOMAN - женщина
+ * @return int текущий пол человека
+ */
+ public function genderAutoDetect()
+ {
+ $this->prepareEverything();
+
+ if (!empty($this->words)){
+ $n=-1;
+ $max_koef=-1;
+ foreach ($this->words as $k=>$word){
+ $genders=$word->getGender();
+ $min=min( $genders );
+ $max=max( $genders );
+ $koef=$max-$min;
+ if ($koef>$max_koef) {
+ $max_koef=$koef;
+ $n=$k;
+ }
+ }
+
+ if ($n>=0){
+ if (isset($this->words[$n]))
+ {
+ $genders=$this->words[$n]->getGender();
+ $min=min( $genders );
+ $max=max( $genders );
+ $this->gender_koef=$max-$min;
+
+ return $this->words[$n]->gender();
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Разбивает строку $fullname на слова и возвращает формат в котором записано имя
+ * Формат:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @param string $fullname строка, для которой необходимо определить формат
+ * @return array формат в котором записано имя массив типа $this->words
+ */
+ private function splitFullName($fullname)
+ {
+
+ $fullname = trim($fullname);
+ $list = explode(' ', $fullname);
+
+ foreach ($list as $word)
+ {
+ $this->words[] = new NCLNameCaseWord($word);
+ }
+
+ $this->prepareEverything();
+ $formatArr = array();
+
+ foreach ($this->words as $word)
+ {
+ $formatArr[] = $word->getNamePart();
+ }
+
+ return $this->words;
+ }
+
+ /**
+ * Разбивает строку $fullname на слова и возвращает формат в котором записано имя
+ * Формат:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @param string $fullname строка, для которой необходимо определить формат
+ * @return string формат в котором записано имя
+ */
+ public function getFullNameFormat($fullname)
+ {
+ $this->fullReset();
+ $words = $this->splitFullName($fullname);
+ $format = '';
+ foreach ($words as $word)
+ {
+ $format .= $word->getNamePart() . ' ';
+ }
+ return $format;
+ }
+
+ /**
+ * Склоняет слово $word по нужным правилам в зависимости от пола и типа слова
+ * @param NCLNameCaseWord $word слово, которое нужно просклонять
+ */
+ private function WordCase(NCLNameCaseWord $word)
+ {
+ $gender = ($word->gender() == NCL::$MAN ? 'man' : 'woman');
+
+ $namepart = '';
+
+ $name_part_letter=$word->getNamePart();
+ switch ($name_part_letter)
+ {
+ case 'F': $namepart = 'Father';
+ break;
+ case 'N': $namepart = 'First';
+ break;
+ case 'S': $namepart = 'Second';
+ break;
+ }
+
+ $method = $gender . $namepart . 'Name';
+
+ //если фамилия из 2х слов через дефис
+ //http://new.gramota.ru/spravka/buro/search-answer?s=273912
+
+ //рабоиваем слово с дефисами на части
+ $tmp=$word->getWordOrig();
+ $cur_words=explode('-', $tmp);
+ $o_cur_words=array();
+
+ $result=array();
+ $last_rule=-1;
+
+ $cnt=count($cur_words);
+ foreach ($cur_words as $k=>$cur_word){
+ $is_norm_rules=true;
+
+ $o_ncw=new NCLNameCaseWord($cur_word);
+ if ( $name_part_letter=='S' && $cnt>1 && $k<$cnt-1 ){
+ //если первая часть фамилии тоже фамилия, то склоняем по общим правилам
+ //иначе не склоняется
+
+ $exclusion=array('тулуз');//исключения
+ $cur_word_=mb_strtolower($cur_word);
+ if ( !in_array($cur_word_, $exclusion ) ){
+ $o_nc = new NCLNameCaseRu();
+ $o_nc->detectNamePart( $o_ncw );
+ $is_norm_rules=( $o_ncw->getNamePart()=='S' );
+ }
+ else {
+ $is_norm_rules=false;
+ }
+ }
+
+ $this->setWorkingWord($cur_word);
+
+ if ($is_norm_rules && $this->$method())
+ {
+ //склоняется
+ $result_tmp=$this->lastResult;
+ $last_rule=$this->lastRule;
+ }
+ else
+ {
+ //не склоняется. Заполняем что есть
+ $result_tmp=array_fill(0, $this->CaseCount, $cur_word);
+ $last_rule=-1;
+ }
+
+ $o_ncw->setNameCases($result_tmp);
+ $o_cur_words[]=$o_ncw;
+ }
+
+ //объединение пачку частей слова в одно слово по каждому падежу
+ foreach ($o_cur_words as $o_ncw){
+ $namecases=$o_ncw->getNameCases();
+ foreach ($namecases as $k=>$namecase){
+ if ( key_exists($k, $result) ) $result[$k]=$result[$k].'-'.$namecase;
+ else $result[$k]=$namecase;
+ }
+ }
+
+ //устанавливаем падежи для целого слова
+ $word->setNameCases($result, false);
+ $word->setRule($last_rule);
+ }
+
+ /**
+ * Производит склонение всех слов, который хранятся в массиве $this->words
+ */
+ private function AllWordCases()
+ {
+ if (!$this->finished)
+ {
+ $this->prepareEverything();
+
+ foreach ($this->words as $word)
+ {
+ $this->WordCase($word);
+ }
+
+ $this->finished = true;
+ }
+ }
+
+ /**
+ * Если указан номер падежа $number, тогда возвращается строка с таким номером падежа,
+ * если нет, тогда возвращается массив со всеми падежами текущего слова.
+ * @param NCLNameCaseWord $word слово для котрого нужно вернуть падеж
+ * @param int $number номер падежа, который нужно вернуть
+ * @return mixed массив или строка с нужным падежом
+ */
+ private function getWordCase(NCLNameCaseWord $word, $number=null)
+ {
+ $cases = $word->getNameCases();
+ if (is_null($number) or $number < 0 or $number > ($this->CaseCount - 1))
+ {
+ return $cases;
+ }
+ else
+ {
+ return $cases[$number];
+ }
+ }
+
+ /**
+ * Если нужно было просклонять несколько слов, то их необходимо собрать в одну строку.
+ * Эта функция собирает все слова указаные в $indexArray в одну строку.
+ * @param array $indexArray индексы слов, которые необходимо собрать вместе
+ * @param int $number номер падежа
+ * @return mixed либо массив со всеми падежами, либо строка с одним падежом
+ */
+ private function getCasesConnected($indexArray, $number=null)
+ {
+ $readyArr = array();
+ foreach ($indexArray as $index)
+ {
+ $readyArr[] = $this->getWordCase($this->words[$index], $number);
+ }
+
+ $all = count($readyArr);
+ if ($all)
+ {
+ if (is_array($readyArr[0]))
+ {
+ //Масив нужно скелить каждый падеж
+ $resultArr = array();
+ for ($case = 0; $case < $this->CaseCount; $case++)
+ {
+ $tmp = array();
+ for ($i = 0; $i < $all; $i++)
+ {
+ $tmp[] = $readyArr[$i][$case];
+ }
+ $resultArr[$case] = implode(' ', $tmp);
+ }
+ return $resultArr;
+ }
+ else
+ {
+ return implode(' ', $readyArr);
+ }
+ }
+ return '';
+ }
+
+ /**
+ * Функция ставит имя в нужный падеж.
+ *
+ * Если указан номер падежа $number, тогда возвращается строка с таким номером падежа,
+ * если нет, тогда возвращается массив со всеми падежами текущего слова.
+ * @param int $number номер падежа
+ * @return mixed массив или строка с нужным падежом
+ */
+ public function getFirstNameCase($number=null)
+ {
+ $this->AllWordCases();
+
+ return $this->getCasesConnected($this->index['N'], $number);
+ }
+
+ /**
+ * Функция ставит фамилию в нужный падеж.
+ *
+ * Если указан номер падежа $number, тогда возвращается строка с таким номером падежа,
+ * если нет, тогда возвращается массив со всеми падежами текущего слова.
+ * @param int $number номер падежа
+ * @return mixed массив или строка с нужным падежом
+ */
+ public function getSecondNameCase($number=null)
+ {
+ $this->AllWordCases();
+
+ return $this->getCasesConnected($this->index['S'], $number);
+ }
+
+ /**
+ * Функция ставит отчество в нужный падеж.
+ *
+ * Если указан номер падежа $number, тогда возвращается строка с таким номером падежа,
+ * если нет, тогда возвращается массив со всеми падежами текущего слова.
+ * @param int $number номер падежа
+ * @return mixed массив или строка с нужным падежом
+ */
+ public function getFatherNameCase($number=null)
+ {
+ $this->AllWordCases();
+
+ return $this->getCasesConnected($this->index['F'], $number);
+ }
+
+ /**
+ * Функция ставит имя $firstName в нужный падеж $CaseNumber по правилам пола $gender.
+ *
+ * Если указан номер падежа $CaseNumber, тогда возвращается строка с таким номером падежа,
+ * если нет, тогда возвращается массив со всеми падежами текущего слова.
+ * @param string $firstName имя, которое нужно просклонять
+ * @param int $CaseNumber номер падежа
+ * @param int $gender пол, который нужно использовать
+ * @return mixed массив или строка с нужным падежом
+ */
+ public function qFirstName($firstName, $CaseNumber=null, $gender=0)
+ {
+ $this->fullReset();
+ $this->setFirstName($firstName);
+ if ($gender)
+ {
+ $this->setGender($gender);
+ }
+ return $this->getFirstNameCase($CaseNumber);
+ }
+
+ /**
+ * Функция ставит фамилию $secondName в нужный падеж $CaseNumber по правилам пола $gender.
+ *
+ * Если указан номер падежа $CaseNumber, тогда возвращается строка с таким номером падежа,
+ * если нет, тогда возвращается массив со всеми падежами текущего слова.
+ * @param string $secondName фамилия, которую нужно просклонять
+ * @param int $CaseNumber номер падежа
+ * @param int $gender пол, который нужно использовать
+ * @return mixed массив или строка с нужным падежом
+ */
+ public function qSecondName($secondName, $CaseNumber=null, $gender=0)
+ {
+ $this->fullReset();
+ $this->setSecondName($secondName);
+ if ($gender)
+ {
+ $this->setGender($gender);
+ }
+
+ return $this->getSecondNameCase($CaseNumber);
+ }
+
+ /**
+ * Функция ставит отчество $fatherName в нужный падеж $CaseNumber по правилам пола $gender.
+ *
+ * Если указан номер падежа $CaseNumber, тогда возвращается строка с таким номером падежа,
+ * если нет, тогда возвращается массив со всеми падежами текущего слова.
+ * @param string $fatherName отчество, которое нужно просклонять
+ * @param int $CaseNumber номер падежа
+ * @param int $gender пол, который нужно использовать
+ * @return mixed массив или строка с нужным падежом
+ */
+ public function qFatherName($fatherName, $CaseNumber=null, $gender=0)
+ {
+ $this->fullReset();
+ $this->setFatherName($fatherName);
+ if ($gender)
+ {
+ $this->setGender($gender);
+ }
+ return $this->getFatherNameCase($CaseNumber);
+ }
+
+ /**
+ * Склоняет текущие слова во все падежи и форматирует слово по шаблону $format
+ * Формат:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @param string $format строка формат
+ * @return array массив со всеми падежами
+ */
+ public function getFormattedArray($format)
+ {
+ if (is_array($format))
+ {
+ return $this->getFormattedArrayHard($format);
+ }
+
+ $length = NCLStr::strlen($format);
+ $result = array();
+ $cases = array();
+ $cases['S'] = $this->getCasesConnected($this->index['S']);
+ $cases['N'] = $this->getCasesConnected($this->index['N']);
+ $cases['F'] = $this->getCasesConnected($this->index['F']);
+
+ for ($curCase = 0; $curCase < $this->CaseCount; $curCase++)
+ {
+ $line = "";
+ for ($i = 0; $i < $length; $i++)
+ {
+ $symbol = NCLStr::substr($format, $i, 1);
+ if ($symbol == 'S')
+ {
+ $line.=$cases['S'][$curCase];
+ }
+ elseif ($symbol == 'N')
+ {
+ $line.=$cases['N'][$curCase];
+ }
+ elseif ($symbol == 'F')
+ {
+ $line.=$cases['F'][$curCase];
+ }
+ else
+ {
+ $line.=$symbol;
+ }
+ }
+ $result[] = $line;
+ }
+ return $result;
+ }
+
+ /**
+ * Склоняет текущие слова во все падежи и форматирует слово по шаблону $format
+ * Формат:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @param array $format массив с форматом
+ * @return array массив со всеми падежами
+ */
+ public function getFormattedArrayHard($format)
+ {
+
+ $result = array();
+ $cases = array();
+ foreach ($format as $word)
+ {
+ $cases[] = $word->getNameCases();
+ }
+
+ for ($curCase = 0; $curCase < $this->CaseCount; $curCase++)
+ {
+ $line = "";
+ foreach ($cases as $value)
+ {
+ $line.=$value[$curCase] . ' ';
+ }
+ $result[] = trim($line);
+ }
+ return $result;
+ }
+
+ /**
+ * Склоняет текущие слова в падеж $caseNum и форматирует слово по шаблону $format
+ * Формат:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @param array $format массив с форматом
+ * @return string строка в нужном падеже
+ */
+ public function getFormattedHard($caseNum=0, $format=array())
+ {
+ $result = "";
+ foreach ($format as $word)
+ {
+ $cases = $word->getNameCases();
+ $result.= $cases[$caseNum] . ' ';
+ }
+ return trim($result);
+ }
+
+ /**
+ * Склоняет текущие слова в падеж $caseNum и форматирует слово по шаблону $format
+ * Формат:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @param string $format строка с форматом
+ * @return string строка в нужном падеже
+ */
+ public function getFormatted($caseNum=0, $format="S N F")
+ {
+ $this->AllWordCases();
+ //Если не указан падеж используем другую функцию
+ if (is_null($caseNum) or !$caseNum)
+ {
+ return $this->getFormattedArray($format);
+ }
+ //Если формат сложный
+ elseif (is_array($format))
+ {
+ return $this->getFormattedHard($caseNum, $format);
+ }
+ else
+ {
+ $length = NCLStr::strlen($format);
+ $result = "";
+ for ($i = 0; $i < $length; $i++)
+ {
+ $symbol = NCLStr::substr($format, $i, 1);
+ if ($symbol == 'S')
+ {
+ $result.=$this->getSecondNameCase($caseNum);
+ }
+ elseif ($symbol == 'N')
+ {
+ $result.=$this->getFirstNameCase($caseNum);
+ }
+ elseif ($symbol == 'F')
+ {
+ $result.=$this->getFatherNameCase($caseNum);
+ }
+ else
+ {
+ $result.=$symbol;
+ }
+ }
+ return $result;
+ }
+ }
+
+ /**
+ * Склоняет фамилию $secondName, имя $firstName, отчество $fatherName
+ * в падеж $caseNum по правилам пола $gender и форматирует результат по шаблону $format
+ * Формат:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @param string $secondName фамилия
+ * @param string $firstName имя
+ * @param string $fatherName отчество
+ * @param int $gender пол
+ * @param int $caseNum номер падежа
+ * @param string $format формат
+ * @return mixed либо массив со всеми падежами, либо строка
+ */
+ public function qFullName($secondName="", $firstName="", $fatherName="", $gender=0, $caseNum=0, $format="S N F")
+ {
+ $this->fullReset();
+ $this->setFirstName($firstName);
+ $this->setSecondName($secondName);
+ $this->setFatherName($fatherName);
+ if ($gender)
+ {
+ $this->setGender($gender);
+ }
+
+ return $this->getFormatted($caseNum, $format);
+ }
+
+ /**
+ * Склоняет ФИО $fullname в падеж $caseNum по правилам пола $gender.
+ * Возвращает результат в таком же формате, как он и был.
+ * @param string $fullname ФИО
+ * @param int $caseNum номер падежа
+ * @param int $gender пол человека
+ * @return mixed либо массив со всеми падежами, либо строка
+ */
+ public function q($fullname, $caseNum=null, $gender=null)
+ {
+ $this->fullReset();
+ $format = $this->splitFullName($fullname);
+ if ($gender)
+ {
+ $this->setGender($gender);
+ }
+
+ return $this->getFormatted($caseNum, $format);
+ }
+
+ /**
+ * Определяет пол человека по ФИО
+ * @param string $fullname ФИО
+ * @return int пол человека
+ */
+ public function genderDetect($fullname)
+ {
+ $this->fullReset();
+ $this->splitFullName($fullname);
+ return $this->genderAutoDetect();
+ }
+
+ /**
+ * Возвращает внутренний массив $this->words каждая запись имеет тип NCLNameCaseWord
+ * @return array Массив всех слов в системе
+ */
+ public function getWordsArray()
+ {
+ return $this->words;
+ }
+
+ /**
+ * Функция пытается применить цепочку правил для мужских имен
+ * @return boolean true - если было использовано правило из списка, false - если правило не было найденым
+ */
+ protected function manFirstName()
+ {
+ return false;
+ }
+
+ /**
+ * Функция пытается применить цепочку правил для женских имен
+ * @return boolean true - если было использовано правило из списка, false - если правило не было найденым
+ */
+ protected function womanFirstName()
+ {
+ return false;
+ }
+
+ /**
+ * Функция пытается применить цепочку правил для мужских фамилий
+ * @return boolean true - если было использовано правило из списка, false - если правило не было найденым
+ */
+ protected function manSecondName()
+ {
+ return false;
+ }
+
+ /**
+ * Функция пытается применить цепочку правил для женских фамилий
+ * @return boolean true - если было использовано правило из списка, false - если правило не было найденым
+ */
+ protected function womanSecondName()
+ {
+ return false;
+ }
+
+ /**
+ * Функция склоняет мужский отчества
+ * @return boolean true - если слово было успешно изменено, false - если не получилось этого сделать
+ */
+ protected function manFatherName()
+ {
+ return false;
+ }
+
+ /**
+ * Функция склоняет женские отчества
+ * @return boolean true - если слово было успешно изменено, false - если не получилось этого сделать
+ */
+ protected function womanFatherName()
+ {
+ return false;
+ }
+
+ /**
+ * Определение пола по правилам имен
+ * @param NCLNameCaseWord $word обьект класса слов, для которого нужно определить пол
+ */
+ protected function GenderByFirstName(NCLNameCaseWord $word)
+ {
+
+ }
+
+ /**
+ * Определение пола по правилам фамилий
+ * @param NCLNameCaseWord $word обьект класса слов, для которого нужно определить пол
+ */
+ protected function GenderBySecondName(NCLNameCaseWord $word)
+ {
+
+ }
+
+ /**
+ * Определение пола по правилам отчеств
+ * @param NCLNameCaseWord $word обьект класса слов, для которого нужно определить пол
+ */
+ protected function GenderByFatherName(NCLNameCaseWord $word)
+ {
+
+ }
+
+ /**
+ * Идетифицирует слово определяе имя это, или фамилия, или отчество
+ * - N - имя
+ * - S - фамилия
+ * - F - отчество
+ * @param NCLNameCaseWord $word обьект класса слов, который необходимо идентифицировать
+ */
+ protected function detectNamePart(NCLNameCaseWord $word)
+ {
+
+ }
+
+ /**
+ * Возвращает версию библиотеки
+ * @return string версия библиотеки
+ */
+ public function version()
+ {
+ return $this->version;
+ }
+
+ /**
+ * Возвращает версию использованого языкового файла
+ * @return string версия языкового файла
+ */
+ public function languageVersion()
+ {
+ return $this->languageBuild;
+ }
}
diff --git a/Library/NCL/NCLNameCaseWord.php b/Library/NCL/NCLNameCaseWord.php
index 8005fd4..ed81e95 100644
--- a/Library/NCL/NCLNameCaseWord.php
+++ b/Library/NCL/NCLNameCaseWord.php
@@ -6,290 +6,306 @@
/**
* NCLNameCaseWord - класс, который служит для хранения всей информации о каждом слове
- *
+ *
* @author Андрей Чайка
- * @version 0.4
+ * @version 0.4.1
* @package NameCaseLib
*/
class NCLNameCaseWord
{
- /**
- * Слово в нижнем регистре, которое хранится в об’єкте класса
- * @var string
- */
- private $word = '';
-
- /**
- * Тип текущей записи (Фамилия/Имя/Отчество)
- * - N - ім’я
- * - S - прізвище
- * - F - по-батькові
- * @var string
- */
- private $namePart = null;
-
- /**
- * Вероятность того, что текущей слово относится к мужскому полу
- * @var int
- */
- private $genderMan = 0;
-
- /**
- * Вероятность того, что текущей слово относится к женскому полу
- * @var int
- */
- private $genderWoman = 0;
-
- /**
- * Окончательное решение, к какому полу относится слово
- * - 0 - не определено
- * - NCL::$MAN - мужской пол
- * - NCL::$WOMAN - женский пол
- * @var int
- */
- private $genderSolved = 0;
-
- /**
- * Маска больших букв в слове.
- *
- * Содержит информацию о том, какие буквы в слове были большими, а какие мальникими:
- * - x - маленькая буква
- * - X - больная буква
- * @var string
- */
- private $letterMask = '';
-
- /**
- * Содержит true, если все слово было в верхнем регистре и false, если не было
- * @var bool
- */
- private $isUpperCase = false;
-
- /**
- * Массив содержит все падежи слова, полученые после склонения текущего слова
- * @var array
- */
- private $NameCases = array();
-
- /**
- * Номер правила, по которому было произведено склонение текущего слова
- * @var int
- */
- private $rule = 0;
-
- /**
- * Создание нового обьекта со словом $word
- * @param string $word слово
- */
- public function __construct($word)
- {
- $this->generateMask($word);
- $this->word = NCLStr::strtolower($word);
- }
-
- /**
- * Генерирует маску, которая содержит информацию о том, какие буквы в слове были большими, а какие маленькими:
- * - x - маленькая буква
- * - X - больная буква
- * @param string $word слово, для которого генерировать маску
- */
- private function generateMask($word)
- {
- $letters = NCLStr::splitLetters($word);
- $mask = array();
- $this->isUpperCase = true;
- foreach ($letters as $letter)
- {
- if (NCLStr::isLowerCase($letter))
- {
- $mask[] = 'x';
- $this->isUpperCase = false;
- }
- else
- {
- $mask[] = 'X';
- }
- }
- $this->letterMask = $mask;
- }
-
- /**
- * Возвращает все падежи слова в начальную маску:
- * - x - маленькая буква
- * - X - больная буква
- */
- private function returnMask()
- {
- if ($this->isUpperCase)
- {
- foreach ($this->NameCases as $index => $case)
- {
- $this->NameCases[$index] = NCLStr::strtoupper($this->NameCases[$index]);
- }
- }
- else
- {
- $splitedMask = $this->letterMask;
- $maskLength = count($splitedMask);
- foreach ($this->NameCases as $index => $case)
- {
- $caseLength = NCLStr::strlen($case);
+ /**
+ * Слово в нижнем регистре, которое хранится в об’єкте класса
+ * @var string
+ */
+ private $word = '';
- $max = min(array($caseLength, $maskLength));
- $this->NameCases[$index] = '';
- for ($letterIndex = 0; $letterIndex < $max; $letterIndex++)
- {
- $letter = NCLStr::substr($case, $letterIndex, 1);
- if ($splitedMask[$letterIndex] == 'X')
- {
- $letter = NCLStr::strtoupper($letter);
- }
- $this->NameCases[$index] .= $letter;
- }
- $this->NameCases[$index] .= NCLStr::substr($case, $max, $caseLength-$maskLength);
- }
- }
- }
-
- /**
- * Сохраняет результат склонения текущего слова
- * @param array $nameCases массив со всеми падежами
- */
- public function setNameCases($nameCases)
- {
- $this->NameCases = $nameCases;
- $this->returnMask();
- }
-
- /**
- * Возвращает массив со всеми падежами текущего слова
- * @return array массив со всеми падежами
- */
- public function getNameCases()
- {
- return $this->NameCases;
- }
-
- /**
- * Возвращает строку с нужным падежом текущего слова
- * @param int $number нужный падеж
- * @return string строка с нужным падежом текущего слова
- */
- public function getNameCase($number)
- {
- if(isset($this->NameCases[$number]))
- {
- return $this->NameCases[$number];
- }
- return false;
- }
-
- /**
- * Расчитывает и возвращает пол текущего слова
- * @return int пол текущего слова
- */
- public function gender()
- {
- if (!$this->genderSolved)
- {
- if ($this->genderMan > $this->genderWoman)
- {
- $this->genderSolved = NCL::$MAN;
- }
- else
- {
- $this->genderSolved = NCL::$WOMAN;
- }
- }
- return $this->genderSolved;
- }
-
- /**
- * Устанавливает вероятности того, что даное слово является мужчиной или женщиной
- * @param int $man вероятность того, что слово мужчина
- * @param int $woman верятность того, что слово женщина
- */
- public function setGender($man, $woman)
- {
- $this->genderMan = $man;
- $this->genderWoman = $woman;
- }
-
- /**
- * Окончательно устанавливает пол человека
- * - 0 - не определено
- * - NCL::$MAN - мужчина
- * - NCL::$WOMAN - женщина
- * @param int $gender пол человека
- */
- public function setTrueGender($gender)
- {
- $this->genderSolved = $gender;
- }
-
- /**
- * Возвращает массив вероятности того, что даное слово является мужчиной или женщиной
- * @return array массив вероятностей
- */
- public function getGender()
- {
- return array(NCL::$MAN => $this->genderMan, NCL::$WOMAN => $this->genderWoman);
- }
-
- /**
- * Устанавливает тип текущего слова
- * Тип слова:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @param string $namePart тип слова
- */
- public function setNamePart($namePart)
- {
- $this->namePart = $namePart;
- }
-
- /**
- * Возвращает тип текущего слова
- * Тип слова:
- * - S - Фамилия
- * - N - Имя
- * - F - Отчество
- * @return string $namePart тип слова
- */
- public function getNamePart()
- {
- return $this->namePart;
- }
-
- /**
- * Возвращает текущее слово.
- * @return string текущее слово
- */
- public function getWord()
- {
- return $this->word;
- }
-
- /**
- * Если уже был расчитан пол для всех слов системы, тогда каждому слову предается окончательное
- * решение. Эта функция определяет было ли принято окончательное решение.
- * @return bool было ли принято окончательное решение по поводу пола текущего слова
- */
- public function isGenderSolved()
- {
- return ($this->genderSolved ? true : false);
- }
-
- /**
- * Устанавливает номер правила по которому склонялось текущее слово.
- * @param int $ruleID номер правила
- */
- public function setRule($ruleID)
- {
- $this->rule = $ruleID;
- }
+ /**
+ * Оригинальное слово
+ * @var string
+ */
+ private $word_orig = '';
+
+ /**
+ * Тип текущей записи (Фамилия/Имя/Отчество)
+ * - N - ім’я
+ * - S - прізвище
+ * - F - по-батькові
+ * @var string
+ */
+ private $namePart = null;
+
+ /**
+ * Вероятность того, что текущей слово относится к мужскому полу
+ * @var int
+ */
+ private $genderMan = 0;
+
+ /**
+ * Вероятность того, что текущей слово относится к женскому полу
+ * @var int
+ */
+ private $genderWoman = 0;
+
+ /**
+ * Окончательное решение, к какому полу относится слово
+ * - 0 - не определено
+ * - NCL::$MAN - мужской пол
+ * - NCL::$WOMAN - женский пол
+ * @var int
+ */
+ private $genderSolved = 0;
+
+ /**
+ * Маска больших букв в слове.
+ *
+ * Содержит информацию о том, какие буквы в слове были большими, а какие мальникими:
+ * - x - маленькая буква
+ * - X - больная буква
+ * @var array
+ */
+ private $letterMask = array();
+
+ /**
+ * Содержит true, если все слово было в верхнем регистре и false, если не было
+ * @var bool
+ */
+ private $isUpperCase = false;
+
+ /**
+ * Массив содержит все падежи слова, полученые после склонения текущего слова
+ * @var array
+ */
+ private $NameCases = array();
+
+ /**
+ * Номер правила, по которому было произведено склонение текущего слова
+ * @var int
+ */
+ private $rule = 0;
+
+ /**
+ * Создание нового обьекта со словом $word
+ * @param string $word слово
+ */
+ public function __construct($word)
+ {
+ $this->word_orig=$word;
+ $this->generateMask($word);
+ $this->word = NCLStr::strtolower($word);
+ }
+
+ /**
+ * Генерирует маску, которая содержит информацию о том, какие буквы в слове были большими, а какие маленькими:
+ * - x - маленькая буква
+ * - X - больная буква
+ * @param string $word слово, для которого генерировать маску
+ */
+ private function generateMask($word)
+ {
+ $letters = NCLStr::splitLetters($word);
+ $mask = array();
+ $this->isUpperCase = true;
+ foreach ($letters as $letter)
+ {
+ if (NCLStr::isLowerCase($letter))
+ {
+ $mask[] = 'x';
+ $this->isUpperCase = false;
+ }
+ else
+ {
+ $mask[] = 'X';
+ }
+ }
+ $this->letterMask = $mask;
+ }
+
+ /**
+ * Возвращает все падежи слова в начальную маску:
+ * - x - маленькая буква
+ * - X - больная буква
+ */
+ private function returnMask()
+ {
+ if ($this->isUpperCase)
+ {
+ foreach ($this->NameCases as $index => $case)
+ {
+ $this->NameCases[$index] = NCLStr::strtoupper($this->NameCases[$index]);
+ }
+ }
+ else
+ {
+ $splitedMask = $this->letterMask;
+ $maskLength = count($splitedMask);
+ foreach ($this->NameCases as $index => $case)
+ {
+ $caseLength = NCLStr::strlen($case);
+
+ $max = min(array($caseLength, $maskLength));
+ $this->NameCases[$index] = '';
+ for ($letterIndex = 0; $letterIndex < $max; $letterIndex++)
+ {
+ $letter = NCLStr::substr($case, $letterIndex, 1);
+ if ($splitedMask[$letterIndex] == 'X')
+ {
+ $letter = NCLStr::strtoupper($letter);
+ }
+ $this->NameCases[$index] .= $letter;
+ }
+ $this->NameCases[$index] .= NCLStr::substr($case, $max, $caseLength-$maskLength);
+ }
+ }
+ }
+
+ /**
+ * Сохраняет результат склонения текущего слова
+ * @param array $nameCases массив со всеми падежами
+ */
+ public function setNameCases($nameCases, $is_return_mask=true)
+ {
+ $this->NameCases = $nameCases;
+ if ($is_return_mask) $this->returnMask();
+ }
+
+ /**
+ * Возвращает массив со всеми падежами текущего слова
+ * @return array массив со всеми падежами
+ */
+ public function getNameCases()
+ {
+ return $this->NameCases;
+ }
+
+ /**
+ * Возвращает строку с нужным падежом текущего слова
+ * @param int $number нужный падеж
+ * @return string строка с нужным падежом текущего слова
+ */
+ public function getNameCase($number)
+ {
+ if(isset($this->NameCases[$number]))
+ {
+ return $this->NameCases[$number];
+ }
+ return false;
+ }
+
+ /**
+ * Расчитывает и возвращает пол текущего слова
+ * @return int пол текущего слова
+ */
+ public function gender()
+ {
+ if (!$this->genderSolved)
+ {
+ if ($this->genderMan >= $this->genderWoman)
+ {
+ $this->genderSolved = NCL::$MAN;
+ }
+ else
+ {
+ $this->genderSolved = NCL::$WOMAN;
+ }
+ }
+ return $this->genderSolved;
+ }
+
+ /**
+ * Устанавливает вероятности того, что даное слово является мужчиной или женщиной
+ * @param int $man вероятность того, что слово мужчина
+ * @param int $woman верятность того, что слово женщина
+ */
+ public function setGender($man, $woman)
+ {
+ $this->genderMan = $man;
+ $this->genderWoman = $woman;
+ }
+
+ /**
+ * Окончательно устанавливает пол человека
+ * - 0 - не определено
+ * - NCL::$MAN - мужчина
+ * - NCL::$WOMAN - женщина
+ * @param int $gender пол человека
+ */
+ public function setTrueGender($gender)
+ {
+ $this->genderSolved = $gender;
+ }
+
+ /**
+ * Возвращает массив вероятности того, что даное слово является мужчиной или женщиной
+ * @return array массив вероятностей
+ */
+ public function getGender()
+ {
+ return array(NCL::$MAN => $this->genderMan, NCL::$WOMAN => $this->genderWoman);
+ }
+
+ /**
+ * Устанавливает тип текущего слова
+ * Тип слова:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @param string $namePart тип слова
+ */
+ public function setNamePart($namePart)
+ {
+ $this->namePart = $namePart;
+ }
+
+ /**
+ * Возвращает тип текущего слова
+ * Тип слова:
+ * - S - Фамилия
+ * - N - Имя
+ * - F - Отчество
+ * @return string $namePart тип слова
+ */
+ public function getNamePart()
+ {
+ return $this->namePart;
+ }
+
+ /**
+ * Возвращает текущее слово.
+ * @return string текущее слово
+ */
+ public function getWord()
+ {
+ return $this->word;
+ }
+
+ /**
+ * Возвращает текущее оригинальное слово.
+ * @return string текущее слово
+ */
+ public function getWordOrig()
+ {
+ return $this->word_orig;
+ }
+
+ /**
+ * Если уже был расчитан пол для всех слов системы, тогда каждому слову предается окончательное
+ * решение. Эта функция определяет было ли принято окончательное решение.
+ * @return bool было ли принято окончательное решение по поводу пола текущего слова
+ */
+ public function isGenderSolved()
+ {
+ return ($this->genderSolved ? true : false);
+ }
+
+ /**
+ * Устанавливает номер правила по которому склонялось текущее слово.
+ * @param int $ruleID номер правила
+ */
+ public function setRule($ruleID)
+ {
+ $this->rule = $ruleID;
+ }
}
?>
diff --git a/Library/NCL/NCLStr.php b/Library/NCL/NCLStr.php
index fdfddfa..e34c85d 100644
--- a/Library/NCL/NCLStr.php
+++ b/Library/NCL/NCLStr.php
@@ -8,7 +8,7 @@
* Класс содержит функции для работы со строками, которые используются в NCLNameCaseLib
*
* @author Андрей Чайка
- * @version 0.4
+ * @version 0.4.1
* @package NameCaseLib
*/
class NCLStr
diff --git a/Library/NCL.NameCase.ru.php b/Library/NCLNameCaseRu.php
similarity index 60%
rename from Library/NCL.NameCase.ru.php
rename to Library/NCLNameCaseRu.php
index ff3c34e..8d6611a 100644
--- a/Library/NCL.NameCase.ru.php
+++ b/Library/NCLNameCaseRu.php
@@ -17,17 +17,17 @@ require_once dirname(__FILE__) . '/NCL/NCLNameCaseCore.php';
* Система разделения фамилий имен и отчеств для русского языка
*
* @author Андрей Чайка
- * @version 0.4
+ * @version 0.4.1
* @package NameCaseLib
*/
class NCLNameCaseRu extends NCLNameCaseCore
{
+
/**
* Версия языкового файла
* @var string
*/
- protected $languageBuild = '11071017';
-
+ protected $languageBuild = '11072716';
/**
* Количество падежей в языке
* @var int
@@ -52,7 +52,55 @@ class NCLNameCaseRu extends NCLNameCaseCore
* Окончания имен/фамилий, который не склоняются
* @var array
*/
- private $ih = array('их', 'ых', 'ко');
+ private $ih = array('их', 'ых', 'ко', 'уа'/*Бенуа, Франсуа*/);
+ /**
+ * Список окончаний характерных для фамилий
+ * По шаблону {letter}* где * любой символ кроме тех, что в {exclude}
+ * @var array of {letter}=>{exclude}
+ */
+ private $splitSecondExclude = array(
+ 'а' => 'взйкмнпрстфя',
+ 'б' => 'а',
+ 'в' => 'аь',
+ 'г' => 'а',
+ 'д' => 'ар',
+ 'е' => 'бвгдйлмня',
+ 'ё' => 'бвгдйлмня',
+ 'ж' => '',
+ 'з' => 'а',
+ 'и' => 'гдйклмнопрсфя',
+ 'й' => 'ля',
+ 'к' => 'аст',
+ 'л' => 'аилоья',
+ 'м' => 'аип',
+ 'н' => 'ат',
+ 'о' => 'вдлнпря',
+ 'п' => 'п',
+ 'р' => 'адикпть',
+ 'с' => 'атуя',
+ 'т' => 'аор',
+ 'у' => 'дмр',
+ 'ф' => 'аь',
+ 'х' => 'а',
+ 'ц' => 'а',
+ 'ч' => '',
+ 'ш' => 'а',
+ 'щ' => '',
+ 'ъ' => '',
+ 'ы' => 'дн',
+ 'ь' => 'я',
+ 'э' => '',
+ 'ю' => '',
+ 'я' => 'нс'
+ );
+
+ private $names_man=array('Вова', 'Анри', 'Питер', 'Пауль', 'Франц', 'Вильям', 'Уильям',
+ 'Альфонс', 'Ганс', 'Франс', 'Филиппо', 'Андреа', 'Корнелис', 'Фрэнк', 'Леонардо',
+ 'Джеймс', 'Отто', 'жан-пьер', 'Джованни', 'Джозеф', 'Педро', 'Адольф', 'Уолтер',
+ 'Антонио', 'Якоб', 'Эсташ', 'Адрианс', 'Франческо', 'Доменико', 'Ханс', 'Гун',
+ 'Шарль', 'Хендрик', 'Амброзиус', 'Таддео', 'Фердинанд', 'Джошуа', 'Изак', 'Иоганн',
+ 'Фридрих', 'Эмиль', 'Умберто', 'Франсуа', 'Ян', 'Эрнст', 'Георг', 'Карл'
+ );
/**
* Мужские имена, оканчивающиеся на любой ь и -й,
@@ -63,16 +111,23 @@ class NCLNameCaseRu extends NCLNameCaseCore
{
if ($this->in($this->Last(1), 'ьй'))
{
+ if ($this->inNames($this->workingWord, array('Дель')))
+ {
+ $this->Rule(101);
+ $this->makeResultTheSame();
+ return true;
+ }
+
if ($this->Last(2, 1) != "и")
{
$this->wordForms($this->workingWord, array('я', 'ю', 'я', 'ем', 'е'), 1);
- $this->Rule(101);
+ $this->Rule(102);
return true;
}
else
{
$this->wordForms($this->workingWord, array('я', 'ю', 'я', 'ем', 'и'), 1);
- $this->Rule(102);
+ $this->Rule(103);
return true;
}
}
@@ -100,10 +155,16 @@ class NCLNameCaseRu extends NCLNameCaseCore
$this->Rule(202);
return true;
}
+ elseif ($this->inNames($this->workingWord, 'ван'))
+ {
+ $this->Rule(203);
+ $this->makeResultTheSame();
+ return true;
+ }
else
{
$this->wordForms($this->workingWord, array('а', 'у', 'а', 'ом', 'е'));
- $this->Rule(203);
+ $this->Rule(204);
return true;
}
}
@@ -121,16 +182,22 @@ class NCLNameCaseRu extends NCLNameCaseCore
{
if ($this->Last(1) == "а")
{
- if ($this->Last(2, 1) <> 'к')
+ if ($this->inNames($this->workingWord, array('фра', 'Дега', 'Андреа', 'Сёра', 'Сера')))
+ {
+ $this->Rule(301);
+ $this->makeResultTheSame();
+ return true;
+ }
+ elseif (!$this->in($this->Last(2, 1), 'кшгх'))
{
$this->wordForms($this->workingWord, array('ы', 'е', 'у', 'ой', 'е'), 1);
- $this->Rule(301);
+ $this->Rule(302);
return true;
}
else
{
$this->wordForms($this->workingWord, array('и', 'е', 'у', 'ой', 'е'), 1);
- $this->Rule(302);
+ $this->Rule(303);
return true;
}
}
@@ -153,32 +220,45 @@ class NCLNameCaseRu extends NCLNameCaseCore
if ($this->in($this->Last(1), 'ьй'))
{
- if ($this->Last(3, 1) == 'а' or $this->Last(2, 1) == 'е')
+//Слова типа Воробей
+ if ($this->Last(3) == 'бей')
+ {
+ $this->wordForms($this->workingWord, array('ья', 'ью', 'ья', 'ьем', 'ье'), 2);
+ $this->Rule(400);
+ return true;
+ }
+ elseif ($this->Last(3, 1) == 'а' or $this->in($this->Last(2, 1), 'ел'))
{
$this->wordForms($this->workingWord, array('я', 'ю', 'я', 'ем', 'е'), 1);
$this->Rule(401);
return true;
}
- //Толстой -» ТолстЫм
+//Толстой -» ТолстЫм
elseif ($this->Last(2, 1) == 'ы' or $this->Last(3, 1) == 'т')
{
$this->wordForms($this->workingWord, array('ого', 'ому', 'ого', 'ым', 'ом'), 2);
$this->Rule(402);
return true;
}
- //Лесничий
+//Лесничий
elseif ($this->Last(3) == 'чий')
{
$this->wordForms($this->workingWord, array('ьего', 'ьему', 'ьего', 'ьим', 'ьем'), 2);
$this->Rule(403);
return true;
}
- else
+ elseif (!$this->in($this->Last(2, 1), $this->vowels) or $this->Last(2, 1) == 'и')
{
$this->wordForms($this->workingWord, array('ого', 'ому', 'ого', 'им', 'ом'), 2);
$this->Rule(404);
return true;
}
+ else
+ {
+ $this->makeResultTheSame();
+ $this->Rule(405);
+ return true;
+ }
}
return false;
}
@@ -191,14 +271,14 @@ class NCLNameCaseRu extends NCLNameCaseCore
{
if ($this->Last(1) == 'к')
{
- //Если перед слово на ок, то нужно убрать о
- if ($this->Last(2, 1) == 'о')
+//Если перед слово на ок, то нужно убрать о
+ if ($this->Last(4)=='енок' || $this->Last(4)=='ёнок')//Поллок
{
$this->wordForms($this->workingWord, array('ка', 'ку', 'ка', 'ком', 'ке'), 2);
$this->Rule(501);
return true;
}
- if ($this->Last(2, 1) == 'е')
+ if ($this->Last(2, 1) == 'е' && !in_array($this->Last(3, 1), array('р')))//Лотрек
{
$this->wordForms($this->workingWord, array('ька', 'ьку', 'ька', 'ьком', 'ьке'), 2);
$this->Rule(502);
@@ -226,7 +306,14 @@ class NCLNameCaseRu extends NCLNameCaseCore
$this->Rule(601);
return true;
}
- elseif ($this->Last(1) == 'р')
+//е перед ц выпадает
+ elseif ($this->Last(2) == 'ец')
+ {
+ $this->wordForms($this->workingWord, array('ца', 'цу', 'ца', 'цом', 'це'), 2);
+ $this->Rule(604);
+ return true;
+ }
+ elseif ($this->in($this->Last(1), 'цсршмхт'))
{
$this->wordForms($this->workingWord, array('а', 'у', 'а', 'ом', 'е'));
$this->Rule(602);
@@ -249,30 +336,36 @@ class NCLNameCaseRu extends NCLNameCaseCore
{
if ($this->Last(1) == "а")
{
- //Если основа на ш, то нужно и, ей
+ if ($this->inNames($this->workingWord, array('да')))
+ {
+ $this->Rule(701);
+ $this->makeResultTheSame();
+ return true;
+ }
+//Если основа на ш, то нужно и, ей
if ($this->Last(2, 1) == 'ш')
{
$this->wordForms($this->workingWord, array('и', 'е', 'у', 'ей', 'е'), 1);
- $this->Rule(701);
+ $this->Rule(702);
return true;
}
- elseif ($this->in($this->Last(2, 1), 'хк'))
+ elseif ($this->in($this->Last(2, 1), 'хкг'))
{
$this->wordForms($this->workingWord, array('и', 'е', 'у', 'ой', 'е'), 1);
- $this->Rule(702);
+ $this->Rule(703);
return true;
}
else
{
$this->wordForms($this->workingWord, array('ы', 'е', 'у', 'ой', 'е'), 1);
- $this->Rule(703);
+ $this->Rule(704);
return true;
}
}
elseif ($this->Last(1) == "я")
{
$this->wordForms($this->workingWord, array('ой', 'ой', 'ую', 'ой', 'ой'), 2);
- $this->Rule(704);
+ $this->Rule(705);
return true;
}
return false;
@@ -284,10 +377,11 @@ class NCLNameCaseRu extends NCLNameCaseCore
*/
protected function manRule8()
{
- if ($this->in($this->Last(3), $this->ovo) or $this->in($this->Last(2), $this->ih))
+ if ($this->in($this->Last(3), $this->ovo) || $this->in($this->Last(2), $this->ih))
{
+ if ( $this->inNames($this->workingWord, array('рерих')) ) return false;
$this->Rule(8);
- $this->lastResult = array_fill(0, $this->CaseCount, $this->workingWord);
+ $this->makeResultTheSame();
return true;
}
return false;
@@ -300,7 +394,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
*/
protected function womanRule1()
{
- if ($this->Last(1) == "а" and $this->Last(2, 1)!='и')
+ if ($this->Last(1) == "а" and $this->Last(2, 1) != 'и')
{
if (!$this->in($this->Last(2, 1), 'шхкг'))
{
@@ -310,7 +404,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
}
else
{
- //ей посля шиплячего
+//ей посля шиплячего
if ($this->Last(2, 1) == 'ш')
{
$this->wordForms($this->workingWord, array('и', 'е', 'у', 'ей', 'е'), 1);
@@ -408,16 +502,27 @@ class NCLNameCaseRu extends NCLNameCaseCore
}
/**
- * Функция пытается применить цыпочку правил для мужских имен
+ * Функция пытается применить цепочку правил для мужских имен
* @return boolean true - если было использовано правило из списка, false - если правило не было найденым
*/
protected function manFirstName()
{
+ if ($this->inNames($this->workingWord, array('Старший', 'Младший')))
+ {
+ $this->wordForms($this->workingWord, array('его', 'ему', 'его', 'им', 'ем'), 2);
+ return true;
+ }
+ if ($this->inNames($this->workingWord, array('Мариа')))
+ {
+ //Альфонс Мария Муха
+ $this->wordForms($this->workingWord, array('и', 'и', 'ю', 'ей', 'ии'), 1);
+ return true;
+ }
return $this->RulesChain('man', array(1, 2, 3));
}
/**
- * Функция пытается применить цыпочку правил для женских имен
+ * Функция пытается применить цепочку правил для женских имен
* @return boolean true - если было использовано правило из списка, false - если правило не было найденым
*/
protected function womanFirstName()
@@ -426,7 +531,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
}
/**
- * Функция пытается применить цыпочку правил для мужских фамилий
+ * Функция пытается применить цепочку правил для мужских фамилий
* @return boolean true - если было использовано правило из списка, false - если правило не было найденым
*/
protected function manSecondName()
@@ -435,7 +540,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
}
/**
- * Функция пытается применить цыпочку правил для женских фамилий
+ * Функция пытается применить цепочку правил для женских фамилий
* @return boolean true - если было использовано правило из списка, false - если правило не было найденым
*/
protected function womanSecondName()
@@ -444,12 +549,12 @@ class NCLNameCaseRu extends NCLNameCaseCore
}
/**
- * Функция склоняет мужский отчества
+ * Функция склоняет мужские отчества
* @return boolean true - если слово было успешно изменено, false - если не получилось этого сделать
*/
protected function manFatherName()
- {
- //Проверяем действительно ли отчество
+ {
+//Проверяем действительно ли отчество
if ($this->inNames($this->workingWord, 'Ильич'))
{
$this->wordForms($this->workingWord, array('а', 'у', 'а', 'ом', 'е'));
@@ -469,7 +574,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
*/
protected function womanFatherName()
{
- //Проверяем действительно ли отчество
+//Проверяем действительно ли отчество
if ($this->Last(2) == 'на')
{
$this->wordForms($this->workingWord, array('ы', 'е', 'у', 'ой', 'е'), 1);
@@ -494,7 +599,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
{
$man+=0.9;
}
- if ($this->in($this->Last(2), array('он', 'ов', 'ав', 'ам', 'ол', 'ан', 'рд', 'мп')))
+ if ($this->in($this->Last(2), array('он', 'ов', 'ав', 'ам', 'ол', 'ан', 'рд', 'мп', 'по'/*Филиппо*/, 'до'/*Леонардо*/, 'др', 'рт')))
{
$man+=0.3;
}
@@ -507,7 +612,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
$man+=0.02;
}
- if ($this->in($this->Last(2), array('вь', 'фь', 'ль')))
+ if ($this->in($this->Last(2), array('вь', 'фь', 'ль', 'на')))
{
$woman+=0.1;
}
@@ -522,7 +627,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
$man+=0.01;
}
- if ($this->in($this->Last(3), array('лья', 'вва', 'ока', 'ука', 'ита')))
+ if ($this->in($this->Last(3), array('лья', 'вва', 'ока', 'ука', 'ита', 'эль'/*Рафаэль, Габриэль*/, 'реа'/*Андреа*/)))
{
$man+=0.2;
}
@@ -532,15 +637,31 @@ class NCLNameCaseRu extends NCLNameCaseCore
$woman+=0.15;
}
- if ($this->in($this->Last(3), array('лия', 'ния', 'сия', 'дра', 'лла', 'кла', 'опа')))
+ if ($this->in($this->Last(3), array('лия', 'ния', 'сия', 'дра', 'лла', 'кла', 'опа', 'вия')))
{
$woman+=0.5;
}
- if ($this->in($this->Last(4), array('льда', 'фира', 'нина', 'лита')))
+ if ($this->in($this->Last(4), array('льда', 'фира', 'нина', 'лита', 'алья')))
{
$woman+=0.5;
}
+
+ if ($this->inNames($this->workingWord, $this->names_man))
+ {
+ $man += 10;
+ }
+
+ if ($this->inNames($this->workingWord, array('Бриджет', 'Элизабет', 'Маргарет', 'Джанет', 'Жаклин', 'Эвелин')))
+ {
+ $woman += 10;
+ }
+
+ //Исключение для Берил Кук, которая женщина
+ if ($this->inNames($this->workingWord, array('Берил')))
+ {
+ $woman += 0.05;
+ }
$word->setGender($man, $woman);
}
@@ -561,7 +682,7 @@ class NCLNameCaseRu extends NCLNameCaseCore
$man+=0.4;
}
- if ($this->in($this->Last(3), array('ова', 'ина', 'ева', 'ёва', 'ына')))
+ if ($this->in($this->Last(3), array('ова', 'ина', 'ева', 'ёва', 'ына', 'мин')))
{
$woman+=0.4;
}
@@ -602,47 +723,240 @@ class NCLNameCaseRu extends NCLNameCaseCore
protected function detectNamePart(NCLNameCaseWord $word)
{
$namepart = $word->getWord();
+ $length = NCLStr::strlen($namepart);
$this->setWorkingWord($namepart);
- //Считаем вероятность
+//Считаем вероятность
$first = 0;
$second = 0;
$father = 0;
- //если смахивает на отчество
+//если смахивает на отчество
if ($this->in($this->Last(3), array('вна', 'чна', 'вич', 'ьич')))
{
$father+=3;
}
- //Похоже на имя
- if ($this->in($this->Last(3), array('тин', 'тын')))
+ if ($this->in($this->Last(2), array('ша')))
{
$first+=0.5;
}
- //Исключения
- if ($this->inNames($namepart, array('Лев', 'Яков', 'Мальвина', 'Антонина', 'Альбина', 'Агриппина', 'Каллиник', 'Маша', 'Ольга', 'Еремей', 'Фаина', 'Лазарь', 'Екатерина', 'Карина', 'Марина', 'Валентина', 'Кристина', 'Исак', 'Исаак', 'Валентин', 'Константин', 'Мартин', 'Устин', 'Калина', 'Аделина', 'Алина', 'Ангелина', 'Галина', 'Каролина', 'Павлина', 'Полина', 'Элина', 'Мина', 'Нина', 'Ева', 'Ирина', 'Элькин')))
+ if ($this->in($this->Last(3), array('эль'/*Рафаэль, Габриэль*/)))
+ {
+ $first+=0.5;
+ }
+
+ /**
+ * буквы на которые никогда не заканчиваются имена
+ */
+ if ($this->in($this->Last(1), 'еёжхцочшщъыэю'))
+ {
+ /**
+ * Просто исключения
+ */
+ if ($this->inNames($namepart, array('Мауриц')))
+ {
+ $first += 10;
+ }
+ else {
+ $second += 0.3;
+ }
+ }
+
+ /**
+ * Используем массив характерных окончаний
+ */
+ if (isset($this->splitSecondExclude[$this->Last(2, 1)]))
+ {
+ if (!$this->in($this->Last(1), $this->splitSecondExclude[$this->Last(2, 1)]))
+ {
+ $second += 0.4;
+ }
+ }
+
+ /**
+ * Сокращенные ласкательные имена типя Аня Галя и.т.д.
+ */
+ if ($this->Last(1) == 'я' and $this->in($this->Last(3, 1), $this->vowels))
+ {
+ $first += 0.5;
+ }
+
+ /**
+ * Не бывает имен с такими предпоследними буквами
+ */
+ if ($this->in($this->Last(2, 1), 'жчщъэю'))
+ {
+ $second += 0.3;
+ }
+
+ /**
+ * Слова на мягкий знак. Существует очень мало имен на мягкий знак. Все остальное фамилии
+ */
+ if ($this->Last(1) == 'ь')
+ {
+ /**
+ * Имена типа нинЕЛь адЕЛь асЕЛь
+ */
+ if ($this->Last(3, 2) == 'ел')
+ {
+ $first += 0.7;
+ }
+ /**
+ * Просто исключения
+ */
+ elseif ($this->inNames($namepart, array('Лазарь', 'Игорь', 'Любовь')))
+ {
+ $first += 10;
+ }
+ /**
+ * Если не то и не другое, тогда фамилия
+ */
+ else
+ {
+ $second += 0.3;
+ }
+ }
+ /**
+ * Если две последних букв согласные то скорее всего это фамилия
+ */
+ elseif ($this->in($this->Last(1), $this->consonant . 'ь') and $this->in($this->Last(2, 1), $this->consonant . 'ь'))
+ {
+ /**
+ * Практически все кроме тех которые оканчиваются на следующие буквы
+ */
+ if (!$this->in($this->Last(2), array('др', 'кт', 'лл', 'пп', 'рд', 'рк', 'рп', 'рт', 'тр')))
+ {
+ $second += 0.25;
+ }
+ }
+
+ /**
+ * Слова, которые заканчиваются на тин
+ */
+ if ($this->Last(3) == 'тин' and $this->in($this->Last(4, 1), 'нст'))
+ {
+ $first += 0.5;
+ }
+
+//Исключения
+ if ($this->inNames($namepart, array('Лев', 'Яков', 'Вова', 'Маша', 'Ольга', 'Еремей',
+ 'Исак', 'Исаак', 'Ева', 'Ирина', 'Элькин', 'Мерлин', 'Макс', 'Алекс',
+ 'Мариа'/*Альфонс Мариа Муха*/,
+ 'Бриджет', 'Элизабет', 'Маргарет', 'Джанет', 'Жаклин', 'Эвелин'/*женские иностранные*/))
+ || $this->inNames($namepart, $this->names_man)
+ )
{
$first+=10;
}
- //похоже на фамилию
- if ($this->in($this->Last(2), array('ов', 'ин', 'ев', 'ёв', 'ый', 'ын', 'ой', 'ко', 'ук', 'як', 'ца', 'их', 'ик', 'ун', 'ок', 'ша', 'ая', 'га', 'ёк', 'аш', 'ив', 'юк', 'ус', 'це', 'ак', 'бр', 'яр', 'де', 'ых', 'уз')))
+
+
+ /**
+ * Фамилии которые заканчиваются на -ли кроме тех что типа натАли и.т.д.
+ */
+ if ($this->Last(2) == 'ли' and $this->Last(3, 1) != 'а')
{
$second+=0.4;
}
- if ($this->in($this->Last(3), array('ова', 'ева', 'ёва', 'ына', 'тых', 'рик', 'вач', 'аха', 'шен', 'мей', 'арь', 'вка', 'шир', 'бан', 'тин', 'чий', 'ина', 'гай')))
+ /**
+ * Фамилии на -як кроме тех что типа Касьян Куприян + Ян и.т.д.
+ */
+ if ($this->Last(2) == 'ян' and $length > 2 and !$this->in($this->Last(3, 1), 'ьи'))
{
$second+=0.4;
}
- if ($this->in($this->Last(4), array('ьник', 'нчук', 'тник', 'кирь', 'ский', 'шена')))
+ /**
+ * Фамилии на -ур кроме имен Артур Тимур
+ */
+ if ($this->Last(2) == 'ур')
+ {
+ if (!$this->inNames($namepart, array('Артур', 'Тимур')))
+ {
+ $second += 0.4;
+ }
+ }
+
+ /**
+ * Разбор ласкательных имен на -ик
+ */
+ if ($this->Last(2) == 'ик')
+ {
+ /**
+ * Ласкательные буквы перед ик
+ */
+ if ($this->in($this->Last(3, 1), 'лшхд'))
+ {
+ $first += 0.3;
+ }
+ else
+ {
+ $second += 0.4;
+ }
+ }
+
+ /**
+ * Разбор имен и фамилий, который заканчиваются на ина
+ */
+ if ($this->Last(3) == 'ина')
+ {
+ /**
+ * Все похожие на Катерина и Кристина
+ */
+ if ($this->in($this->Last(7), array('атерина', 'ристина')))
+ {
+ $first+=10;
+ }
+ /**
+ * Исключения
+ */
+ elseif ($this->inNames($namepart, array('Мальвина', 'Антонина', 'Альбина', 'Агриппина', 'Фаина', 'Карина', 'Марина', 'Валентина', 'Калина', 'Аделина', 'Алина', 'Ангелина', 'Галина', 'Каролина', 'Павлина', 'Полина', 'Элина', 'Мина', 'Нина', 'Дина')))
+ {
+ $first+=10;
+ }
+ /**
+ * Иначе фамилия
+ */
+ else
+ {
+ $second += 0.4;
+ }
+ }
+
+ /**
+ * Имена типа Николай
+ */
+ if ($this->Last(4) == 'олай')
+ {
+ $first += 0.6;
+ }
+
+ /**
+ * Фамильные окончания
+ */
+ if ($this->in($this->Last(2), array('ов', 'ин', 'ев', 'ёв', 'ый', 'ын', 'ой', 'ук', 'як', 'ца', 'ун', 'ок', 'ая', 'ёк', 'ив', 'ус', 'ак', 'яр', 'уз', 'ах', 'ай')))
{
$second+=0.4;
}
+ if ($this->in($this->Last(3), array('ова', 'ева', 'ёва', 'ына', 'шен', 'мей', 'вка', 'шир', 'бан', 'чий', 'кий', 'бей', 'чан', 'ган', 'ким', 'кан', 'мар', 'лис')))
+ {
+ $second+=0.4;
+ }
+
+ if ($this->in($this->Last(4), array('шена')))
+ {
+ $second+=0.4;
+ }
+
+ //исключения и частички
+ if ($this->inNames($namepart, array('да', 'валадон', 'Данбар'))){
+ $second += 10;
+ }
+
$max = max(array($first, $second, $father));
diff --git a/Library/NCL.NameCase.ua.php b/Library/NCLNameCaseUa.php
similarity index 96%
rename from Library/NCL.NameCase.ua.php
rename to Library/NCLNameCaseUa.php
index ad88415..4a4dcd3 100644
--- a/Library/NCL.NameCase.ua.php
+++ b/Library/NCLNameCaseUa.php
@@ -17,7 +17,7 @@ require_once dirname(__FILE__) . '/NCL/NCLNameCaseCore.php';
* Система разделения фамилий имен и отчеств для украинского языка
*
* @author Андрей Чайка
- * @version 0.4
+ * @version 0.4.1
* @package NameCaseLib
*/
class NCLNameCaseUa extends NCLNameCaseCore
@@ -27,7 +27,7 @@ class NCLNameCaseUa extends NCLNameCaseCore
* Версия языкового файла
* @var string
*/
- protected $languageBuild = '11071017';
+ protected $languageBuild = '11071222';
/**
* Количество падежей в языке
* @var int
@@ -81,6 +81,20 @@ class NCLNameCaseUa extends NCLNameCaseCore
return $letter;
}
+ /**
+ * Перевіряє чи символ є апострофом чи не є
+ * @param string(1) $char симпол для перевірки
+ * @return bool true якщо символ є апострофом
+ */
+ private function isApostrof($char)
+ {
+ if ($this->in($char, ' ' . $this->consonant . $this->vowels))
+ {
+ return false;
+ }
+ return true;
+ }
+
/**
* Чергування українських приголосних
* Чергування г к —» ж ч
@@ -274,7 +288,7 @@ class NCLNameCaseUa extends NCLNameCaseCore
//називному відмінку, у непрямих - о: Антона, Антонові
//Чергування і -» о всередині
$osLast = NCLStr::substr($osnova, -1, 1);
- if ($osLast != 'й' and NCLStr::substr($osnova, -2, 1) == 'і' and !$this->in(NCLStr::substr(NCLStr::strtolower($osnova), -4, 4), array('світ', 'цвіт')) and !$this->inNames($this->workingWord, 'Гліб'))
+ if ($osLast != 'й' and NCLStr::substr($osnova, -2, 1) == 'і' and !$this->in(NCLStr::substr(NCLStr::strtolower($osnova), -4, 4), array('світ', 'цвіт')) and !$this->inNames($this->workingWord, 'Гліб') and !$this->in($this->Last(2), array('ік', 'іч')))
{
$osnova = NCLStr::substr($osnova, 0, NCLStr::strlen($osnova) - 2) . 'о' . NCLStr::substr($osnova, -1, 1);
}
@@ -440,7 +454,7 @@ class NCLNameCaseUa extends NCLNameCaseCore
elseif ($this->Last(1) == 'я')
{
- if ($this->in($BeforeLast, $this->vowels))
+ if ($this->in($BeforeLast, $this->vowels) or $this->isApostrof($BeforeLast))
{
$this->wordForms($this->workingWord, array('ї', 'ї', 'ю', 'єю', 'ї', 'є'), 1);
$this->Rule(103);
@@ -519,7 +533,7 @@ class NCLNameCaseUa extends NCLNameCaseCore
}
//Ті що на ськ
- if ($this->Last(1) == 'а' and ($this->in($this->Last(3, 2), array('ов', 'ев', 'єв', 'ив', 'ьк', 'тн', 'рн', 'ин'))))
+ if ($this->Last(1) == 'а' and ($this->in($this->Last(2, 1), 'чнв') or $this->in($this->Last(3, 2), array('ьк'))))
{
$this->wordForms($this->workingWord, array($BeforeLast . 'ої', $BeforeLast . 'ій', $BeforeLast . 'у', $BeforeLast . 'ою', $BeforeLast . 'ій', $BeforeLast . 'о'), 2);
$this->Rule(302);
@@ -664,7 +678,7 @@ class NCLNameCaseUa extends NCLNameCaseCore
$man+=0.4;
}
- if ($this->in($this->Last(3), array('ова', 'ина', 'ева', 'єва', 'іна')))
+ if ($this->in($this->Last(3), array('ова', 'ина', 'ева', 'єва', 'іна', 'мін')))
{
$woman+=0.4;
}
@@ -725,23 +739,23 @@ class NCLNameCaseUa extends NCLNameCaseCore
}
//Исключения
- if ($this->inNames($namepart, array('Лев', 'Гаїна', 'Афіна', 'Антоніна', 'Ангеліна', 'Альвіна', 'Альбіна', 'Аліна', 'Павло', 'Олесь', 'Микола', 'Мая', 'Англеліна', 'Елькін')))
+ if ($this->inNames($namepart, array('Лев', 'Гаїна', 'Афіна', 'Антоніна', 'Ангеліна', 'Альвіна', 'Альбіна', 'Аліна', 'Павло', 'Олесь', 'Микола', 'Мая', 'Англеліна', 'Елькін', 'Мерлін')))
{
$first+=10;
}
//похоже на фамилию
- if ($this->in($this->Last(2), array('ов', 'ін', 'ев', 'єв', 'ий', 'ин', 'ой', 'ко', 'ук', 'як', 'ца', 'их', 'ик', 'ун', 'ок', 'ша', 'ая', 'га', 'єк', 'аш', 'ив', 'юк', 'ус', 'це', 'ак', 'бр', 'яр', 'іл', 'ів', 'ич', 'сь', 'ей', 'нс', 'яс', 'ер', 'ай', 'ян', 'ах', 'ць', 'ющ', 'іс', 'ач', 'уб', 'ох', 'юх', 'ут', 'ча', 'ул', 'вк', 'зь', 'уц', 'їн', 'де', 'уз' /* {endings_name2} */)))
+ if ($this->in($this->Last(2), array('ов', 'ін', 'ев', 'єв', 'ий', 'ин', 'ой', 'ко', 'ук', 'як', 'ца', 'их', 'ик', 'ун', 'ок', 'ша', 'ая', 'га', 'єк', 'аш', 'ив', 'юк', 'ус', 'це', 'ак', 'бр', 'яр', 'іл', 'ів', 'ич', 'сь', 'ей', 'нс', 'яс', 'ер', 'ай', 'ян', 'ах', 'ць', 'ющ', 'іс', 'ач', 'уб', 'ох', 'юх', 'ут', 'ча', 'ул', 'вк', 'зь', 'уц', 'їн', 'де', 'уз', 'юр', 'ік', 'іч', 'ро' /* {endings_name2} */)))
{
$second+=0.4;
}
- if ($this->in($this->Last(3), array('ова', 'ева', 'єва', 'тих', 'рик', 'вач', 'аха', 'шен', 'мей', 'арь', 'вка', 'шир', 'бан', 'чий', 'іна', 'їна', 'ька', 'ань', 'ива', 'аль', 'ура', 'ран', 'ало', 'ола', 'кур', 'оба', 'оль', 'нта', 'зій', 'ґан', 'іло', 'шта', 'юпа', 'рна', 'бла', 'еїн', 'има', 'мар', 'кар', 'оха', 'чур', 'ниш', 'ета', 'тна', 'зур', 'нір', 'йма', 'орж', 'рба', 'іла', 'лас', 'дід', 'роз', 'аба', 'лест', 'мара', 'обка', 'рока', 'сика', 'одна', 'нчар', 'вата', 'ндар', 'грій' /* {endings_name3} */)))
+ if ($this->in($this->Last(3), array('ова', 'ева', 'єва', 'тих', 'рик', 'вач', 'аха', 'шен', 'мей', 'арь', 'вка', 'шир', 'бан', 'чий', 'іна', 'їна', 'ька', 'ань', 'ива', 'аль', 'ура', 'ран', 'ало', 'ола', 'кур', 'оба', 'оль', 'нта', 'зій', 'ґан', 'іло', 'шта', 'юпа', 'рна', 'бла', 'еїн', 'има', 'мар', 'кар', 'оха', 'чур', 'ниш', 'ета', 'тна', 'зур', 'нір', 'йма', 'орж', 'рба', 'іла', 'лас', 'дід', 'роз', 'аба', 'чан', 'ган' /* {endings_name3} */)))
{
$second+=0.4;
}
- if ($this->in($this->Last(4), array('ьник', 'нчук', 'тник', 'кирь', 'ский', 'шена', 'шина', 'вина', 'нина', 'гана', 'гана', 'хній', 'зюба', 'орош', 'орон', 'сило', 'руба' /* {endings_name4} */)))
+ if ($this->in($this->Last(4), array('ьник', 'нчук', 'тник', 'кирь', 'ский', 'шена', 'шина', 'вина', 'нина', 'гана', 'гана', 'хній', 'зюба', 'орош', 'орон', 'сило', 'руба', 'лест', 'мара', 'обка', 'рока', 'сика', 'одна', 'нчар', 'вата', 'ндар', 'грій' /* {endings_name4} */)))
{
$second+=0.4;
}
diff --git a/Tests/Library/GenderDetectname.php b/Tests/Library/GenderDetectname.php
index 2914644..48fda7c 100644
--- a/Tests/Library/GenderDetectname.php
+++ b/Tests/Library/GenderDetectname.php
@@ -1,6 +1,6 @@
diff --git a/Tests/TestGenerator/Template/NCLNameCaseRuTest.main b/Tests/TestGenerator/Template/NCLNameCaseRuTest.main
index a87dca3..3ecd11a 100644
--- a/Tests/TestGenerator/Template/NCLNameCaseRuTest.main
+++ b/Tests/TestGenerator/Template/NCLNameCaseRuTest.main
@@ -1,6 +1,6 @@