Pull to refresh

Автоматический перевод слова в нужный падеж

// Приветствую, хабрамены!



Введение


Тебе приходилось, %username%, видеть на многих проектах надписи:

  • «Подружиться с Дмитрий»
  • «Опубликован Артем» (подразумевалось кем-то)
  • Etc.

Или как, например, сделал ВКонтакте:

  • «Подружиться с Андреем»
  • «Отправить Ярославу подарок»

Сегодня я расскажу, как сделать такую штуку, как «автоматический перевод слова в нужный падеж».


Из курса начальной школы мы все знаем, что существует 6 падежей:

  • Именительный (Кто? Что?)
  • Родительный (Кого? Чего?)
  • Дательный (Кому? Чему?)
  • Винительный (Кого? Что?)
  • Творительный (Кем? Чем?)
  • Предложный (О ком? О чём?)

Все мы понимаем, что без «пинка» в нужное место, слова не будут переводиться в нужный падеж, для этого я и реализовал функцию toCase():



toCase( String str, String case );

Например:

  1. var words={"Мама":"р", "Хабр":"д", "Поросёнок":"в", "Ночь":"т", "Отец":"п"}, result="";
  2. for(var i in words){
  3.     result+=words[i].toUpperCase()+".: "+toCase(i,words[i])+"\n"
  4. }
  5. return result
* This source code was highlighted with Source Code Highlighter.

Выдаст следующее:



Р.: Мамы
Д.: Хабру
В.: Поросёнка
Т.: Ночью
П.: Отце

Развитие событий


Предлагаю сами внутренности функции:

  1. function toCase(str, choice) {
  2.     var strPub = { // правила для окончаний
  3.         "а": ["ы", "е", "у", "ой", "е"],
  4.         "(ш/ж/к/ч)а": ["%и", "%е", "%у", "%ой", "%е"],
  5.         "б/в/м/г/д/л/ж/з/к/н/п/т/ф/ч/ц/щ/р/х": ["%а", "%у", "%а", "%ом", "%е"],
  6.         "и": ["ей", "ям", "%", "ями", "ях"],
  7.         "ый": ["ого", "ому", "%", "ым", "ом"],
  8.         "й": ["я", "ю", "я", "ем", "е"],
  9.         "о": ["а", "у", "%", "ом", "е"],
  10.         "с/ш": ["%а", "%у", "%", "%ом", "%е"],
  11.         "ы": ["ов", "ам", "%", "ами", "ах"],
  12.         "ь": ["я", "ю", "я", "ем", "е"],
  13.         "уль": ["ули", "уле", "улю", "улей", "уле"],
  14.         "(ч/ш/д/т)ь": ["%и", "%и", "%ь", "%ью", "%и"],
  15.         "я": ["и", "е", "ю", "ей", "е"]
  16.     },
  17.     cases = { // номера для падежей, не считая Именительный
  18.         "р": 0,
  19.         "д": 1,
  20.         "в": 2,
  21.         "т": 3,
  22.         "п": 4
  23.     },
  24.     exs = { // исключения, сколько символов забирать с конца
  25.         "ц": 2,
  26.         "ок": 2
  27.     },
  28.     lastIndex,reformedStr,forLong,splitted,groupped,forPseudo;
  29.     for(var i in strPub){
  30.         if(i.length > 1 && str.slice(-i.length) == i){ // для окончаний, длиной >1
  31.             lastIndex = i;
  32.             reformedStr = str.slice(0, -lastIndex.length);
  33.             break;
  34.         }
  35.         else if(/[\(\)]+/g.test(i)){ // фича: группировка окончаний
  36.             i.replace(/\(([^\(\)]+)\)([^\(\)]+)?/g, function(a, b, c){
  37.                 splitted = b.split("/");
  38.                 for(var o = 0; o < splitted.length; o++){
  39.                     groupped = splitted[o] + c;
  40.                     strPub[groupped] = strPub[i];
  41.                     if(str.slice(-groupped.length) == groupped){
  42.                         for(var x = 0, eachSplited = strPub[groupped];x < eachSplited.length; x++){
  43.                             eachSplited[x] = eachSplited[x].replace("%", splitted[o]);
  44.                         }
  45.                         reformedStr = str.slice(0, -groupped.length);
  46.                         forPseudo = groupped;
  47.                     }
  48.                 }
  49.             })
  50.         }
  51.         else{ // дефолт
  52.             lastIndex = str.slice(-1);
  53.             reformedStr = str.slice(0, -(forPseudo || lastIndex).length);
  54.         }
  55.         if(/\//.test(i) && !(/[\(\)]+/g.test(i)) && new RegExp(lastIndex).test(i))forLong = i; // группированные окончания, разделающиеся слешем
  56.         for(var o in exs){ // поиск исключений
  57.             if(str.slice(-o.length) == o)reformedStr = str.slice(0, -exs[o]);
  58.         }
  59.     }
  60.     return reformedStr + strPub[(forPseudo || forLong || lastIndex)][cases[choice]].replace("%", lastIndex)
  61. }
* This source code was highlighted with Source Code Highlighter.

В объекте с правилами (strPub) знак процента (%) принимает 2 вида, в зависимости от:

  • если в правиле имеются скобки, то знак (%) будет равен их содержимому;
  • иначе будет равен всем символам правил

Конечно, идея и реализация далеко не идеальны, поэтому буду рад вашим фидбэкам.


Попробовать (демо).


Всех с наступившими новогодними праздниками!

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.