Advertisement
Guest User

Names.js

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