Advertisement
Guest User

Names.php

a guest
Dec 7th, 2012
1,966
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 11.22 KB | None | 0 0
  1. <?php
  2.  
  3.  
  4. /**
  5.  * Склонение русских имён и фамилий
  6.  *
  7.  * var rn = new RussianName('Паниковский Михаил Самуэльевич');
  8.  * rn.fullName(rn.gcaseRod); // Паниковского Михаила Самуэльевича
  9.  *
  10.  * Список констант по падежам см. ниже в коде.
  11.  *
  12.  * Пожалуйста, присылайте свои уточнения мне на почту. Спасибо.
  13.  *
  14.  * @version  0.1.3
  15.  * @author   Johnny Woo <agalkin@agalkin.ru>
  16.  */
  17.  
  18.  
  19. class lastName {
  20.     var $exceptions = array(
  21.         "   дюма,тома,дега,люка,ферма,гамарра,петипа . . . . .",
  22.         '   гусь,ремень,камень,онук,богода,нечипас,долгопалец,маненок,рева,кива . . . . .',
  23.         '   вий,сой,цой,хой -я -ю -я -ем -е'
  24.     );
  25.     var $suffixes = array(
  26.         'f  б,в,г,д,ж,з,й,к,л,м,н,п,р,с,т,ф,х,ц,ч,ш,щ,ъ,ь . . . . .',
  27.         'f  ска,цка  -ой -ой -ую -ой -ой',
  28.         'f  ая       --ой --ой --ую --ой --ой',
  29.         '   ская     --ой --ой --ую --ой --ой',
  30.         'f  на       -ой -ой -у -ой -ой',
  31.  
  32.         '   иной -я -ю -я -ем -е',
  33.         '   уй   -я -ю -я -ем -е',
  34.         '   ца   -ы -е -у -ей -е',
  35.  
  36.         '   рих  а у а ом е',
  37.  
  38.         '   ия                      . . . . .',
  39.         '   иа,аа,оа,уа,ыа,еа,юа,эа . . . . .',
  40.         '   их,ых                   . . . . .',
  41.         '   о,е,э,и,ы,у,ю           . . . . .',
  42.  
  43.         '   ова,ева            -ой -ой -у -ой -ой',
  44.         '   га,ка,ха,ча,ща,жа  -и -е -у -ой -е',
  45.         '   ца  -и -е -у -ей -е',
  46.         '   а   -ы -е -у -ой -е',
  47.  
  48.         '   ь   -я -ю -я -ем -е',
  49.  
  50.         '   ия  -и -и -ю -ей -и',
  51.         '   я   -и -е -ю -ей -е',
  52.         '   ей  -я -ю -я -ем -е',
  53.  
  54.         '   ян,ан,йн   а у а ом е',
  55.  
  56.         '   ынец,обец  --ца --цу --ца --цем --це',
  57.         '   онец,овец  --ца --цу --ца --цом --це',
  58.  
  59.         '   ц,ч,ш,щ   а у а ем е',
  60.  
  61.         '   ай  -я -ю -я -ем -е',
  62.         '   ой  -го -му -го --им -м',
  63.         '   ах,ив   а у а ом е',
  64.  
  65.         '   ший,щий,жий,ний  --его --ему --его -м --ем',
  66.         '   кий,ый   --ого --ому --ого -м --ом',
  67.         '   ий       -я -ю -я -ем -и',
  68.  
  69.         '   ок  --ка --ку --ка --ком --ке',
  70.         '   ец  --ца --цу --ца --цом --це',
  71.  
  72.         '   в,н   а у а ым е',
  73.         '   б,г,д,ж,з,к,л,м,п,р,с,т,ф,х   а у а ом е'
  74.     );
  75. }
  76.  
  77. class firstName {
  78.     var $exceptions = array (
  79.         '   лев    --ьва --ьву --ьва --ьвом --ьве',
  80.         '   павел  --ла  --лу  --ла  --лом  --ле',
  81.         'm  шота   . . . . .',
  82.         'f  рашель,нинель,николь,габриэль,даниэль   . . . . .'
  83.     );
  84.     var $suffixes = array(
  85.         '   е,ё,и,о,у,ы,э,ю   . . . . .',
  86.         'f  б,в,г,д,ж,з,й,к,л,м,н,п,р,с,т,ф,х,ц,ч,ш,щ,ъ   . . . . .',
  87.  
  88.         'f  ь   -и -и . ю -и',
  89.         'm  ь   -я -ю -я -ем -е',
  90.  
  91.         '   га,ка,ха,ча,ща,жа  -и -е -у -ой -е',
  92.         '   а   -ы -е -у -ой -е',
  93.         '   ия  -и -и -ю -ей -и',
  94.         '   я   -и -е -ю -ей -е',
  95.         '   ей  -я -ю -я -ем -е',
  96.         '   ий  -я -ю -я -ем -и',
  97.         '   й   -я -ю -я -ем -е',
  98.         '   б,в,г,д,ж,з,к,л,м,н,п,р,с,т,ф,х,ц,ч    а у а ом е'
  99.     );
  100. }
  101.  
  102. class middleName {
  103.     var $exceptions = array();
  104.     var $suffixes = array (
  105.         '   ич   а  у  а  ем  е',
  106.         '   на  -ы -е -у -ой -е'
  107.     );
  108. }
  109.        
  110. class Rules {
  111.     var $lastName, $firstName, $middleName;
  112.     function Rules(){
  113.         $this->lastName = new lastName();
  114.         $this->firstName = new firstName();
  115.         $this->middleName = new middleName();
  116.     }
  117. }
  118.  
  119. class RussianNameProcessor {
  120.     var $sexM = 'm';
  121.     var $sexF = 'f';
  122.     var $gcaseIm =  'nominative';      var $gcaseNom = 'nominative';      // именительный
  123.     var $gcaseRod = 'genitive';        var $gcaseGen = 'genitive';        // родительный
  124.     var $gcaseDat = 'dative';                                       // дательный
  125.     var $gcaseVin = 'accusative';      var $gcaseAcc = 'accusative';      // винительный
  126.     var $gcaseTvor = 'instrumentative';var $gcaseIns = 'instrumentative'; // творительный
  127.     var $gcasePred = 'prepositional';  var $gcasePos = 'prepositional';   // предложный
  128.    
  129.     var $fullNameSurnameLast = false;
  130.     var $ln = '', $fn = '', $mn = '', $sex = '';
  131.  
  132.     var $rules;
  133.     var $initialized = false;
  134.  
  135.     function init(){
  136.         if ( $this -> initialized ) {
  137.             return;
  138.         }
  139.         $this->rules = new rules();
  140.         $this->prepareRules();
  141.         $this -> initialized = true;
  142.     }
  143.    
  144.     function RussianNameProcessor ($lastName, $firstName = NULL, $middleName = NULL, $sex = NULL) {
  145.         $this->init();
  146.         if (!isset($firstName)) {
  147.             preg_match("/^\s*(\S+)(\s+(\S+)(\s+(\S+))?)?\s*$/", $lastName, $m);
  148.             if(!$m) exit("Cannot parse supplied name");
  149.             if($m[5] && preg_match("/(ич|на)$/",$m[3]) && !preg_match("/(ич|на)$/",$m[5])) {
  150.                 // Иван Петрович Сидоров
  151.                 $lastName = $m[5];
  152.                 $firstName = $m[1];
  153.                 $middleName = $m[3];
  154.                 $this -> fullNameSurnameLast = true;
  155.             } else {
  156.                 // Сидоров Иван Петрович
  157.                 $lastName = $m[1];
  158.                 $firstName = $m[3];
  159.                 $middleName = $m[5];
  160.             }
  161.         }
  162.         $this -> ln = $lastName;
  163.         if (isset($firstName)) $this -> fn = $firstName;
  164.         else $this -> fn = '';
  165.         if (isset($middleName)) $this -> mn = $middleName;
  166.         else $this -> mn = '';
  167.         if (isset($sex)) $this -> sex = $sex;
  168.         else $this -> sex = $this -> getSex();
  169.        
  170.         return;
  171.     }
  172.  
  173.     function prepareRules () {
  174.         foreach ( array("lastName", "firstName", "middleName") as $type ) {
  175.             foreach(array("suffixes" ,"exceptions") as $key) {
  176.                 $n = count($this -> rules->$type->$key);
  177.                 for ($i = 0; $i < $n; $i++) {
  178.                     $this->rules->$type->{$key}[$i] = $this->rule($this->rules->$type->{$key}[$i]);
  179.                 }
  180.             }
  181.         }
  182.     }
  183.  
  184.     function rule ($rule) {
  185.         preg_match("/^\s*([fm]?)\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/", $rule, $m);
  186.             if ( $m ) return array (
  187.             "sex" => $m[1],
  188.             "test" => split(',', $m[2]),
  189.             "mods" => array ($m[3], $m[4], $m[5], $m[6], $m[7])
  190.         );
  191.         return false;
  192.     }
  193.  
  194.     // склоняем слово по указанному набору правил и исключений
  195.     function word ($word, $sex, $wordType, $gcase) {
  196.         // исходное слово находится в именительном падеже
  197.         if( $gcase == $this->gcaseNom) return $word;
  198.  
  199.         // составные слова
  200.         if( preg_match("/[-]/", $word)) {
  201.                 $list = $word->split('-');
  202.                 $n = count($list);
  203.                 for($i = 0; $i < $n; $i++) {
  204.                         $list[$i] = $this->word($list[$i], $sex, $wordType, $gcase);
  205.                 }
  206.                 return join('-', $list);
  207.         }
  208.  
  209.         // Иванов И. И.
  210.         if ( preg_match("/^[А-ЯЁ]\.?$/i", $word)) return $word;
  211.         $this->init();
  212.         $rules = $this->rules->$wordType;
  213.  
  214.         if ( $rules->exceptions) {
  215.                 $pick = $this->pick($word, $sex, $gcase, $rules->exceptions, true);
  216.                 if ( $pick ) return $pick;
  217.         }
  218.         $pick = $this->pick($word, $sex, $gcase, $rules->suffixes, false);
  219.         if ($pick) return $pick;
  220.         else return $word;
  221.     }
  222.  
  223.     // выбираем из списка правил первое подходящее и применяем
  224.     function pick ($word, $sex, $gcase, $rules, $matchWholeWord) {
  225.         $wordLower = strtolower($word);
  226.         $n = count($rules);
  227.         for($i = 0; $i < $n; $i++) {
  228.             if ( $this->ruleMatch($wordLower, $sex, $rules[$i], $matchWholeWord)) {
  229.                 return $this->applyMod($word, $gcase, $rules[$i]);
  230.             }
  231.         }
  232.         return false;
  233.     }
  234.  
  235.  
  236.     // проверяем, подходит ли правило к слову
  237.     function ruleMatch ($word, $sex, $rule, $matchWholeWord) {
  238.         if ($rule["sex"] == $this->sexM && $sex == $this->sexF) return false; // male by default
  239.         if ($rule["sex"] == $this->sexF && $sex != $this->sexF) return false;
  240.         $n = count($rule["test"]);
  241.         for($i = 0; $i < $n; $i++) {
  242.             $test = $matchWholeWord ? $word : substr($word, max(strlen($word) - strlen($rule["test"][$i]), 0));
  243.             if($test == $rule["test"][$i]) return true;
  244.         }
  245.         return false;
  246.     }
  247.  
  248.     // склоняем слово (правим окончание)
  249.     function applyMod($word, $gcase, $rule) {
  250.         switch($gcase) {
  251.             case $this -> gcaseNom: $mod = '.'; break;
  252.             case $this -> gcaseGen: $mod = $rule["mods"][0]; break;
  253.             case $this -> gcaseDat: $mod = $rule["mods"][1]; break;
  254.             case $this -> gcaseAcc: $mod = $rule["mods"][2]; break;
  255.             case $this -> gcaseIns: $mod = $rule["mods"][3]; break;
  256.             case $this -> gcasePos: $mod = $rule["mods"][4]; break;
  257.             default: exit("Unknown grammatic case: "+gcase);
  258.         }
  259.         $n = strlen($mod);
  260.         for($i = 0; $i < $n; $i++) {
  261.             $c = substr($mod, $i, 1);
  262.             switch($c) {
  263.                 case '.': break;
  264.                 case '-': $word = substr($word, 0, strlen($word) - 1); break;
  265.                 default: $word .= $c;
  266.             }
  267.         }
  268.         return $word;
  269.     }
  270.    
  271.     function getSex() {
  272.         if( strlen($this->mn) > 2) {
  273.             switch(substr($this->mn, -2)) {
  274.                 case 'ич': return $this->sexM;
  275.                 case 'на': return $this->sexF;
  276.             }
  277.         }
  278.         return '';
  279.     }
  280.    
  281.     function fullName($gcase) {
  282.         $tmpstr = ($this->fullNameSurnameLast ? '' : $this->lastName($gcase) . ' ')
  283.             . $this -> firstName($gcase) . ' ' . $this -> middleName($gcase)
  284.             . ($this -> fullNameSurnameLast ? ' ' . $this -> lastName($gcase) : '');
  285.         return preg_replace("/^ +| +$/", '', $tmpstr);
  286.     }
  287.    
  288.     function lastName($gcase) {
  289.         return $this->word($this -> ln, $this -> sex, 'lastName', $gcase);  
  290.     }
  291.    
  292.     function firstName($gcase) {
  293.         return $this->word($this -> fn, $this -> sex, 'firstName', $gcase);
  294.     }
  295.    
  296.     function middleName($gcase) {
  297.         return $this->word($this -> mn, $this -> sex, 'middleName', $gcase);
  298.     }
  299. }
  300.  
  301. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement