Petrovich просклоняет русские имена

    Вам часто приходится иметь дело со склонением имён пользователей на русском языке? При рассылке писем, при отображении страниц и упоминаний, при генерации рекламных объявлений? Скорее всего, приходится изворачиваться и писать все сообщения в именительном падеже — Иванов Пётр Сергеевич.

    Это не всегда удобно, не всегда красиво, не всегда уместно. Русский язык одарён богатой морфологией, которая несколько затрудняет его автоматическую обработку. Всем известно, что антропонимы, как полагается именам существительным, подчиняются всем правилам словообразования.

    Для решения этой проблемы при использовании Ruby существует Petrovich — удобная легковесная библиотека для автомагического склонения русскоязычных имён, фамилий и отчеств.



    Суть


    В основе алгоритма Petrovich лежит база правил словообразования, составленная вручную. Прикладному программисту работать с библиотекой будет очень легко: на входе указывается слово в канонической форме, на выходе получается слово запрошенного рода и падежа.

    Использование


    Базовый синтаксис достаточно прост для понимания.

    petrovich = Petrovich.new(:male)
    petrovich.lastname('Иванов', :dative)      # => Иванову
    petrovich.firstname('Пётр', :dative)       # => Петру
    petrovich.middlename('Сергеевич', :dative) # => Сергеевичу
    

    Как можно заметить, имеется два параметра, которые описывают поведение анализатора: в конструктор класса Petrovich передаётся пол, вторым параметром метода склонения передаётся падеж.

    Во-первых, половая принадлежность имени. Petrovich рассматривает три варианта:
    • мужской пол, :male;
    • женский пол, :female;
    • «андрогинный» пол, :androgynous, при котором форма фамилии не зависит от пола человека. Например, Прокопенко.

    Во-вторых, требуемый падеж. Допустимые падежи, изменяющие слово, описаны ниже в таблице.
    Падеж Характеризующий вопрос Обозначение
    Родительный Кого? Чего? genitive
    Дательный Кому? Чему? dative
    Винительный Кого? Что? accusative
    Творительный Кем? Чем? instrumental
    Предложный О ком? О чём? prepositional
    Имеется возможность подмешать модуль Petrovich::Extension в любой класс. Это особенно полезно при использовании ActiveRecord и подобных ORM.

    class User < ActiveRecord::Base
      include Petrovich::Extension
    
      petrovich :firstname  => :my_firstname,
                :middlename => :my_middlename,
                :lastname   => :my_lastname,
                :gender     => :my_gender
    
      def my_firstname
        'Пётр'
      end
    
      def my_middlename
        'Ашотович'
      end
    
      def my_lastname
        'Бонч-Соколов-Скаля'
      end
    
      # Если пол не был указан, используется автоматическое определение
      # пола на основе отчества. Если отчество также не было указано,
      # пытаемся определить правильное склонение на основе файла правил.
      def my_gender
        :male # :male, :female или :androgynous
      end
    end
    

    При помощи метода petrovich указываются методы, представляющие фамилию, имя и отчество. В данном примере указано, что метод my_firstname представляет имя, метод my_lastname представляет фамилию, метод my_middlename представляет отчество. Ничто не мешает подмешать модуль и в обычный класс, всё будет работать так же хорошо. В целевой класс будут добавлены методы с падежами, описанными в таблице.

    user = User.new
    user.my_firstname           # => Пётр
    
    user.my_firstname_genitive  # => Петра
    user.my_middlename_genitive # => Ашотовича
    user.my_lastname_genitive   # => Бонч-Соколова-Скаля
    

    Некоторые особенности русского правописания учитываются достаточно хорошо.

    Оценка аккуратности


    Ради приличия, проводилась оценка аккуратности склонения слов. В качестве эталона взят список фамилий и их форм из морфологического словаря АОТ. Аккуратность оценивалась на основе обработки 88 314 примеров по формуле

    ,

    где case — падеж, gender — пол, Vcase,gender — количество верных словоизменений для указанного падежа и рода, Ncase,gender — общее количество примеров для указанного падежа и рода.

    На момент написания статьи наблюдается средняя аккуратность 99,6614% на основе обработки 88 314 примеров. Детали приведены ниже в таблице. Эта информация может быть полезна при использовании Petrovich в боевых условиях.
    Пол / Падеж Родительный Дательный Винительный Творительный Предложный
    Мужской 99,7137% 99,7386% 99,7635% 97,9858% 99,7261%
    Женский 99,9102% 99,9401% 99,9701% 99,4636% 99,9401%

    Реквизиты


    Репозиторий на GitHub располагается по адресу petrovich/petrovich-ruby. Библиотека распространяется на условиях MIT License. Авторами библиотеки являются Андрей Козлов (Bonch) и Дмитрий Усталов (dustalov).

    Чтобы установить Petrovich и использовать его в собственных приложениях, достаточно выполнить gem install petrovich или дописать соответствующую строчку в Gemfile.

    Веб-интерфейс


    Приятно, что Андрей Ситник (Iskin) из «Злых Марсиан» сделал классный интерфейс, который позволяет играться с Petrovich прямо из браузера.



    В настоящий момент интерфейс доступен по адресу http://petrovich.nlpub.ru/.

    Портирование


    Было бы здорово, если разработчики, работающие с другими языками программирования, портировали бы эту библиотеку на свои языки. Мы рады ответить на любые вопросы по Petrovich. В общем случае, начать портирование можно с нашей базы правил.

    Спасибо, что дочитали до конца!

    Иллюстрации с Петровичем принадлежат Андрею Бильжо, автору комиксов про Петровича.
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 141

      +9
      Не хватает определение пола ещё по имени, там точность будет меньше, но тоже полезно.
        +2
        Да, это было бы полезно.
          +7
          Пол лучше определять по отчеству — славянские отчества у женщин кончаются на «а», у мужчин, напротив — никогда не кончаются на «а».
          Писал лет 10 назад библиотеку склонений ФИО в родительный падеж, исключение — ФИО содержащие «оглы/кызы» — собственно оглы у мужчин, кызы — у женщин, так что тоже 100% попадание в пол.

          По фамилии — такое-же правило, у женщин всегда «а», кроме несклоняемых фамилий. Но тут и человек не угадает по фамилии :-)
            0
            Короче, надо сделать определение пола по всем трём параметрам. Тогда точность максимальная будет.
              +4
              В настоящее время пол определяется по отчеству при помощи очень простой эвристики.
                +19
                — А ты помнишь свое отчество?
                — Только последние три буквы...
                ©

                UPD. Еще бы не возникла эта ссылка в каментах.
                  +2
                  В одном из моих приложений есть необходимость определять пол, причем отчества может и не быть, или фамилии, я просто взял у твиттера открытые словари имен (русских и иностранных), и гружу в хэш-лист, точность определения близка к 100%, за исключением сложных случаев, например, когда женская фамилия совпадает с мужским именем. Ну и скорость при использовании HashSet не будет уступать использованию вашей простой эвристики.
                    0
                    Клёво. Где можно посмотреть словари и результаты?
                    0
                    Кстати, еще идея для имен без отчества:
                    1) определяем по словарю мужских/женских имен
                    2) если имя нет в словаре, ищем людей с такой же фамилией и определяем пол по ним
                    3) если найдено не меньше 3х, заносим имя в словарь

                    Пример:
                    Елена Иванова — имя «Елена» в словаре женское, значит женщина
                    Даздраперма Иванова — ищем выборку с фамилией «Иванова», смотрим пол большинства (например, 5 — женщин, 1 — ошибочно заведенный мужик), и решаем, что Даздраперма — женщина. Так как найдено больше 3х, то заносим «Даздраперма» в словарь женских имён.
                    +1
                    Предлагаю более железобетонный вариант:

                      def detect_gender(midname)
                        tail = UnicodeUtils.downcase(midname[-4, 4])
                        if (tail[-1]=='а') or (tail=='кызы')
                          'female'
                        else
                          'male'
                        end
                      end
                    

                    Пола 'androgynous' не бывает, и неопределённость можно списать на мужчин.
                    0
                    По фамилии — такое-же правило, у женщин всегда «а», кроме несклоняемых фамилий.

                    Иван Васильевич Бунша. Фамилия склоняется.
                      0
                      Я же написал — «кроме несклоняемых фамилий».
                      «Бунша» — несклоняемая фамилия, поэтому по одной фамилии определить нельзя никак.
                        +1
                        Склоняемая, я же написал.

                        Родительный: Это шляпа Бунши (не «Это шляпа Бунша»).
                        Дательный: Отдай книгу Бунше (не «Отдай книгу Бунша»).
                        Винительный: Поступила жалоба на Буншу (не «Поступила жалоба на Бунша»).
                        Творительный: Забор был покрашен Буншей (не «Забор был покрашен Бунша»).
                        Предложный: Написали статью о Бунше (не «Написали статью о Бунша»).

                        Собственно, по фамилии пол определить нельзя, потому что и у мужчины фамилия может заканчиваться на «а». И именно это я и иллюстрирую.
                      0
                      По имени тоже можно ) Насколько помню только одно женское имя не оканчивается не на а или я.
                      0
                      Гадя Петрович Хренова…

                      UPD: Я всегда буду читать все комментарии перед тем как постить…
                        0
                        Я, когда такое писал, определял по отчеству. У отчеств разнообразие было меньше.
                        0
                        Неплохо было бы веб-сервисом сделать, например.
                          +1
                          Веб-интерфейс по ссылке в посте имеет API. В исходниках описано, как с ним работать. Возможно, будет проще подсмотреть параметры AJAX-запросов.
                          +1
                          Герцен в творительном неправильно, должно быть: Герценом. Источник.
                            +1
                            Спасибо, поправим.
                              +1
                              Все прочие мужские фамилии, имеющие основы на согласные и нулевое окончание в именительном падеже (на письме они кончаются согласной буквой, ь или й), кроме фамилий на -ых, -их, склоняются как существительные второго склонения мужского рода

                              Я правильно понял, что мужские фамилии, оканчивающиеся на -ых, -их не склоняются?
                                0
                                Верно. Примеры: Синих, Больных.
                                  0
                                  А к иностранным фамилиям это относится? Например: Цветцих.
                                    +2
                                    Вообще, надо сделать дополнительный флаг: русский/иностранец.

                                    Пушкин → Пушкиным (русский)
                                    Раскин → Раскином (американец)
                                    Иванов → Ивановым (русский)
                                    Сальхов → Сальховом (швед)
                                      0
                                      Безусловно, подобные флаги имели бы ценность и здорово помогали при обработки слов. Однако я не уверен, что их должен задавать конечный пользователь.
                                        0
                                        Такова, ёлки зелёные, жизнь. И Юникод так сложен, потому что сложна наша письменность.
                                        Может быть, для isMale и isRussian придётся делать троичную логику: true/false/unknown, с угадыванием, например, по словарю.
                                          0
                                          На мой взгляд, такие вещи лучше решать привлечением дополнительных словарей, при обнаружении слова в которых выставлять флаги. Как это сейчас делается для двойных русских фамилий.
                                            +1
                                            Но и словарь, собака, не опора: что будет, если написать: Лоис Макмастер Буджолд?
                                            А это женщина!
                                              0
                                              Подскажите, в чем проблема для словаря в данном конкретном случае? Ведь Лоис — вполне себе женское имя.
                                                0
                                                В том, что это не русское имя? В словаре все имена мира не собрать, и ошибки неизбежны.
                                      0
                                      Сейчас мне сложно вспомнить какие-то исключения, спать хочется. Всё зависит от фамилии, происхождения, словоупотребительной практики. Возможно, статья на «Грамоте» поможет пролить свет.
                                    +2
                                    В пункте 13.1.6 написано, что по строгим нормам не склоняются, но в разговорной речи более чем допускается. Пример: слушали лекции Черныха, сдавали экзамены и зачеты Черныху.
                                    +1
                                    Уже отправил в баг-трекер, у меня тоже фамилия в творительном не так склоняется (Быхун).
                                    +2
                                    Библиотека несложна, «особой рубиновой магии» там вроде бы нет, и, кажется, портация на С++ должна занять день.
                                    Сложнее будет написать юнит-тесты.
                                      0
                                      В репозитории сейчас имеются какие-то примитивные тесты на RSpec, но я их особо не читал. Процедура автоматической оценки по словарю АОТ открыта и реализована как Rake-задача rake evaluate.
                                        0
                                        Будь я автором библиотеки на C++, я бы сделал два тестовых проекта.

                                        Один, на Google Test, будет демонстрировать работу каждого из правил. Для этого будет запускаться «расширенная» версия функции, а затем проверка, что сработало именно это правило.

                                        Второй, простой консольный, будет брать информацию из большого списка CSV и проверять, что всё работает.
                                      +5
                                      Библиотека супер.
                                      Думаю, на днях (в крайнем случае на след. выходных) попробую портировать на C#/.NET
                                      Отпишу в комментарии по результатам.
                                        +1
                                        Спасибо! Буду рад помочь советом или ответом.
                                          +1
                                          Обязательно свяжусь с вами, если возникнут вопросы.
                                          В руби я не впервой, код довольно понятен.
                                        –12
                                        Алексей Савицкий

                                        род.
                                        Алексея Савицкия
                                        дат.
                                        Алексею Савицкию
                                        вин.
                                        Алексея Савицкия
                                        тво.
                                        Алексеем Савицкием
                                        пре.
                                        Алексее Савицкии

                                        Бредятина, правда?)
                                          +31
                                          Полная. Особенно если учесть, что имя и фамилия перепутаны местами.
                                          +1
                                          Пример неправильного склонения:

                                          Папа-Христозопуло Васисуалий

                                          род.
                                          Папы-Христозопуло Васисуалия
                                          дат.
                                          Папе-Христозопуло Васисуалию
                                          вин.
                                          Папу-Христозопуло Васисуалия
                                          тво.
                                          Папой-Христозопуло Васисуалием
                                          пре.
                                          Папе-Христозопуло Васисуалии
                                            0
                                            Принято. Правильно ли я понимаю, что ожидается неизменное «Папа-Христозопуло»?
                                              +1
                                              Насколько я помню, это как раз правильное поведение.
                                              — Части составных фамилий склоняются независимо, так что рассматриваем обе части отдельно
                                              — Иностранные фамилии мужского рода склоняются (женского — нет, так что на Василисе Папе-Христозопуло был бы сбой, но это к делу не относится :) )
                                              — часть «Христозопуло», как и все фамилии на -о, не склоняется (см., например, www.gramota.ru/spravka/letters/?rub=rubric_482 )
                                              — часть «Папа» — зависит от происхождения, но, если корень славянский, то склоняется.

                                              Да и вообще, требовать 100% верной работы от лингвистического алгоритма бессмысленно. В языке есть множество неформализованных моментов, а к фамилиям это относится вдвойне.
                                            +1
                                            В веб интерфейсе используется шрифт Cuprum, а с ним буквы скачут. По крайней мере Chromium/linux

                                              +1
                                              Я плохо разбираюсь во фронтэнде, но не уверен, что проблема на нашей стороне. У меня под Linux в Google Chrome и Firefox всё в полном порядке.
                                                0
                                                Сайт как раз разрабатывался на Хроме в Убунте, у вас скорее проблема со сглаживанием шрифтов, которая вызывает у некоторых шрифтов артефакты. Я использую хитинг Slight и сглаживание Rgba.
                                                  0
                                                  Странно, но у меня такая штука только с один шрифтом — Cuprum с google fonts, сам сталкивался просто.
                                                  0
                                                  Там ещё проблема с Хрома/Хромиума на некоторых дистрибутивах. Он иногда не видит системные настройки сглаживания/хитинга шрифтов и использует весьма ужасные. Лечиться созданием ~/.font.config и перезапуском браузера.
                                                  +1
                                                  Иванов Гаврило получил от Розенталя указание склоняться, а не так как сейчас.
                                                    0
                                                    Спасибо. Посмотрим, что можно сделать.
                                                    +2
                                                    Вот это расклад

                                                    род.
                                                    Гади Петровича Хренова
                                                    дат.
                                                    Гаде Петровичу Хренова
                                                    вин.
                                                    Гадю Петровича Хренова
                                                    тво.
                                                    Гадей Петровичом Хренова
                                                    пре.
                                                    Гаде Петровиче Хренова
                                                      +1
                                                      Нет. В демонстрационном интерфейсе порядок слов задаётся как ФИО. Подозреваю, что это совсем не то, что написано выше.
                                                        +1
                                                        У вас порядок неправильный, но и при правильном порядке неправильно склоняет

                                                        род.
                                                        Хреновой Гади Петровича
                                                        дат.
                                                        Хреновой Гаде Петровичу
                                                        вин.
                                                        Хренову Гадю Петровича
                                                        тво.
                                                        Хреновой Гадей Петровичем
                                                        пре.
                                                        Хреновой Гаде Петровиче
                                                          +4
                                                          На мой взгляд, пример некорректен. Быть может, всё-таки, имелась в виду женщина по имени Хренова Гада Петровна? С ней всё хорошо. Не бывает женщин с отчеством «Петрович».
                                                            +11
                                                              +3
                                                              — О, у нас сегодня романтика-свечи, масло…
                                                              — Слышь, Петрович, отойди от капота!

                                                              — Почему ты так и не предложил выйти за тебя?
                                                              — Бля, Петрович, прораб же сказал, что сменами нельзя меняться!

                                                              — Помнишь, как мы кончили одновременно?
                                                              — Бля, Петрович, помню, конечно, мы же в параллельных классах учились.

                                                              — Теперь расслабься и смотри, как я беру его в ротик и нежно отсасываю…
                                                              — Бля, Петрович, давай быстрее бензин перельем и поедем уже!

                                                              — А засунь в обе дырочки по пальчику…
                                                              — Бля, Петрович, это же розетка, хочешь, чтобы меня током пиздануло?!

                                                              — Да я отвечаю это вкусно! В Таиланде все их едят. «Жареные гусеницы» называется!
                                                              — Бля, Петрович, и на чем теперь трактор то будет ездить?!

                                                              — Ой! посмотри как у меня сосочки затвердели! Это наверно от холода…
                                                              — Бля, Петрович, да мне похуй, давай работать уже!

                                                              — Что ты со мной делаешь? Опять тушь потекла…
                                                              — Бля, Петрович, с твоими кривыми руками мы чертеж никогда не закончим!

                                                              — Может, еще немножко поваляемся? Я сейчас без трусиков…
                                                              — Бля, Петрович, подымайся, тельник в зубы и бегом! Магистраль прорвало!
                                                        +1
                                                        Спасибо за прекрасную библиотеку.

                                                        Русскоязычные комментарии на GitHub режут глаз.
                                                          +1
                                                          Пожалуйста, пользуйтесь. Увы, русский язык в комментариях к коду — не единственная проблема, но самая заметная.
                                                            +3
                                                            Я в Ruby новичок, бывает очень интересно читать чужой код и разбираться, что к чему. По вашему коду возник вопрос.

                                                            Посмотрел структуру основного файла. Не могу понять, почему именно так сделано:

                                                            Пол можно определять синглтон-классом: Petrovich.detect_gender('Ильич'). Для всего остального требуется создать инстанс, но стиль работы с этим инстансом точно такой же, как с синглтоном: Petrovich.new.firstname('Кузьма', :dative).

                                                            Не логичнее ли было бы либо всё сделать синглтоном (при этом пол можно принимать опциональным аргументом), либо создавать инстанс индивидуально для фамилии? Например, как-то так:

                                                            user = Petrovich.new('Томас Ильич Эдисон')
                                                            puts user.fullname(:dative)   # => Томаса Ильича Эдисона
                                                            puts user.middlename(:dative) # => Ильича
                                                            puts user.to_s                # => Томас Ильич Эдисон
                                                            
                                                              0
                                                              Логичнее (только я бы сделал немного иначе).
                                                              У автора очень странный код.
                                                                0
                                                                А как бы вы сделали?
                                                                0
                                                                Это сделано, чтобы учитывать ФИО как отдельные строки.
                                                                  +1
                                                                  Я не понимаю. Объясните, пожалуйста, на примере и в сравнении с моим примером.
                                                                    +1
                                                                    Вот например, когда нужно просклонять только имя:

                                                                    p = Petrovich.new(:male)
                                                                    p.firstname('Пётр', :dative)  # => Петру
                                                                    
                                                                      +3
                                                                      Ну, и чем это лучше метода класса?

                                                                      Petrovich.firstname('Пётр', :dative, :male)  # => Петру
                                                                      

                                                                      Зачем создавать инстанс? Я так понимаю, у вас будет болтаться два инстанса: для мужского и женского родов, и непонятно, какие сущности они представляют и зачем их держать в памяти.
                                                                        0
                                                                        Мне нравится такой вариант. Bonch, что скажешь?
                                                              +6
                                                              Комментарии в коде специально по-русски писал. Библиотека ведь только для русскоязычных. Глупо было бы писать комментарии на английском.
                                                                –2
                                                                Мне кажется, что это не совсем правильно. Комментарии на русском лучше оставить только в файле с правилами для русского языка.
                                                                  0
                                                                  Ничуть не глупо. Английский — международный язык общения. А для программиста английский — единый язык любой документации.

                                                                  Представьте, фрилансите вы, и вам заказчик дает библиотеку с документацией на болгарском. «Ну окуеть теперь!» скажете вы и будете правы.
                                                                    +4
                                                                    Библиотека ведь только для русскоязычных.


                                                                    Ну, почему. Какой-нибудь англоязычный сервис пытается писать по-русски, но коверкает имена. Можно было бы им написать: «Hey, guys, stop abusing Russian language. You can use insanely great Petrovich library after all.» Но там комментарии на русском.
                                                                  +5
                                                                  Оу, уже хочу портировать на PHP :)
                                                                    +3
                                                                    Было бы любопытно сравнить с этой библиотекой
                                                                      0
                                                                      использовал её в своём проекте. ниразу не подвела.
                                                                    0
                                                                    багрепорт: не учитываются запятые в исходной строке.
                                                                    Пример: Бердымухамедов, Гурбангулы Мяликгулыевич

                                                                    род. Бердымухамедов, Гурбангулы Мяликгулыевича

                                                                    Если убрать запятую:
                                                                    род. Бердымухамедова Гурбангулы Мяликгулыевича
                                                                      0
                                                                      Я не в теме, но может быть лучше сделать склонение по выборке из базы «88 314 примеров»?
                                                                        +1
                                                                        Попробовал Джона Леннона. Творительный получался либо Джоным Ленноном, либо Ленноным Джоном. Какой-то Ленноный Джон получается :) Справедливости ради — имя не русское.
                                                                        РодЛеннона Джона
                                                                        дат.
                                                                        Леннону Джону
                                                                        вин.
                                                                        Леннона Джона
                                                                        тво.
                                                                        Ленноным Джоном
                                                                        пре.
                                                                        Ленноне Джоне
                                                                          0
                                                                          Спасибо за отчёт. Здесь с нашей стороны будет проще добавить исключение. Вообще, не помешала бы выгруженная откуда-нибудь статистика по фамилиям. Это поможет уточнить правила.
                                                                            0
                                                                            Персонаж комедии «Иван Васильевич меняет профессию» Бунша Иван Васильевич:

                                                                            род. Буншы Ивана Васильевича — должно быть Бунши.
                                                                            твор. Буншой Иваном Васильевичем — должно быть Буншей.

                                                                            Остальные верные.
                                                                          0
                                                                          Вы простите если пропустил, но все же спрошу, как используется surnames.tsv с базой фамилий?
                                                                            0
                                                                            Во время работы — никак. Это таблица с эталонами для проведения автоматической оценки при помощи rake evaluate.
                                                                          • UFO just landed and posted this here
                                                                              +3
                                                                              Несмотря на то, что алгоритм реально работает — название сайта наиболее полно отражает впечатление от кода.
                                                                                0
                                                                                Вы не понимаете, это же старая школа! =)

                                                                                PS Ссылка пришлась в тему холивара, где я отстаивал точку зрения, что 1С почти необратимо формирует дурной стиль программирования у человека, и он теряет способность понять, чем такой код плох.
                                                                                • UFO just landed and posted this here
                                                                              +2
                                                                              Некая девушка ломает отображение на сайте. Имя ей Иванова-Петрова-Водкина Евлампия Понтелеевна!
                                                                              +2
                                                                              Одобряю
                                                                              • UFO just landed and posted this here
                                                                                  +1
                                                                                  Спасибо, исправим.
                                                                                    0
                                                                                    Готово.
                                                                                      +1
                                                                                      В Корее довольно часто встречается фамилия «Ё», происходит она из китайского языка и при написании иероглифами делится на три клана. В 2000 году найдено 75,196 однофамильцев. Помимо Кореи буква «Ё» выступает в роли фамилии и в России, в переводе с французского означает «глаза». В России она считается очень редкой, насчитывается всего три ее носителя.
                                                                                      samogo.net/articles.php?id=2113
                                                                                        0
                                                                                        Да, можно добавить рядом.
                                                                                          +1
                                                                                          А зачем добавлять? Все однобуквенные не склоняются же.
                                                                                    +1
                                                                                    Исправим. Вот только наберем побольше фидбэка и займемся выпуском следующей версии.
                                                                                    +1
                                                                                    Мне нужно было единоразово просклонять названия товаров, и я, подглядывая в исходники петровича (не без ctrl-c, ctrl-v), сделал сыроватый гем для склонения заголовков и определительных словосочетаний — github.com/estum/russian_inflect.

                                                                                    С моими задачами гем справился, но есть немало слов, которые он просклоняет неправильно (например, слово «палец»).
                                                                                    Я пока слабо представляю, как внести в rules.yml все правила из ru.wiktionary.org/w/index.php?oldid=2775434, чтобы они не противоречили друг другу и чтобы не пришлось явно указывать род и число. Нужно хотя бы забить в тесты примеры из викисловаря и потом пытаться подогнать результат, но, увы, на это пока нет свободного времени.

                                                                                    Пардоньте за некошерные ссылки.
                                                                                      0
                                                                                      Отличная работа! Увы, задача склонения в общем виде достаточно нетривиальна. Для этого существуют специальные анализаторы, лемматизаторы и «склоняторы». Сегодня для Ruby нет даже близкого аналога pymorphy2, а я со своим Myaso всё никак не сдвинусь с мёртвой точки, потому что практически нет времени на программирование.
                                                                                        +1
                                                                                        Я когда-то пользовался Яндекс склонятором, вот даже гем есть https://github.com/yaroslav/yandex_inflect
                                                                                          +1
                                                                                          Склонятор — всё, и довольно давно. Соответственно, yandex_inflect тоже не работает. Я его первым делом попробовал, перед тем как начать неистово кодить свой гем.
                                                                                            0
                                                                                            Увы, Яндекс отключил свой сервис достаточно давно.
                                                                                        +1
                                                                                        Очень похоже на алгоритмы библиотеки padeg, про которую я писал тут в прошлом году (а это тесты: test-rlab.rhcloud.com/). Только там все правила в коде, а тут — в «таблицах», и это очень хорошо: такую библиотеку проще портировать. Если говорить о портируемости, то не мешало бы еще бы поработать над форматом таблиц, какой-нибудь общеупотребимый формат, тот же xml или json.
                                                                                        А чего пока нет — это склонения китайских ФИО, плюс склонения должностей и подразделений.
                                                                                        Авторы, примете пожертвования в виде исходных кодов?
                                                                                          0
                                                                                          Конечно, присоединяйтесь! Для портируемости в среднесрочной перспективе лучше использовать JSON. Изначально Petrovich не задумывался как инструмент для склонения должностей и подразделений, но было бы интересно посмотреть на реализацию. Если там можно обойтись относительно простыми правилами без использования чего-то хитрого или нетривиального, то было бы круто.
                                                                                            +2
                                                                                            Не надо менять формат, YAML привычен в руби, для таких вещей очень удобен и конвертируется в xml или json легким движением руки.
                                                                                              +1
                                                                                              Согласен.
                                                                                                0
                                                                                                Справедливо.
                                                                                              0
                                                                                              А вообще это хитрый способь узнать настоящие фамилии хабрапользователей))
                                                                                                +2
                                                                                                Не буду перечислять все недоработки, приведу одну:
                                                                                                род. Кима Ира-Сена

                                                                                                www.gramota.ru/slovari/info/ag/sklon/
                                                                                                5.2. В составных именах и фамилиях вьетнамских, корейских, бирманских, камбоджийских, китайских и др. склоняется последняя часть: Нгуен Тхи Бинь, Нгуен Тхи Биня [эн] (вьетнамск. гос. деятель); КИМ ЁН НАМ, Ким Ён Нама (сев.-кор. гос. деятель); 〈…〉
                                                                                                  +1
                                                                                                  И этому правилу даже есть объяснение. Дело в том, что первая часть таких имён (по крайней мере корейских) — это фамилия (Ким), которая не склоняется. А _две_ остальные части (Ир Сен) — это имя (которое склоняется). И в принципе вполне корректно (хотя и непривычно) записывать в таком виде — Ким Ирсен, Ким Ченыр и т.д.
                                                                                                  +1
                                                                                                  Есть недоработки с окончаниями фамилий в творительном падеже "- ем" vs "-ём".
                                                                                                  Примеры: Кромвель — Кромвелем, Коваль-Ковалем (-нормально).
                                                                                                  Но: Костыль- Костылем (-не корректно), должно быть — Костылём.
                                                                                                    0
                                                                                                    Спасибо, исправим.
                                                                                                      0
                                                                                                      Тут, наверное, зависит от ударения:
                                                                                                      Кост'ыль — Костылём
                                                                                                      К'остыль — К'остылем
                                                                                                        0
                                                                                                        Вроде не обязательно использовать «ё» в окончаниях при склонении, а как правильно прочитать окончание и так понятно [*]. Лучше в таких случаях склонять везде с «е», чем пропустить какое-нибудь исключение и получить неправильную «ё». Короче, имхо, это несущественно.

                                                                                                        * Задумался над творитерным падежом слова «холуй» — я бы произнёс «холуем», но в викисловаре указано «холуём».
                                                                                                        И так же с другими словами оканчивающимися на «уй» ;)
                                                                                                        +5
                                                                                                        освящаю этот тред
                                                                                                          +1
                                                                                                          Вот волшебный код на 1с. Я не понимаю, как он работает, но работает:

                                                                                                          слабонервным не смотреть
                                                                                                          // Функция для склонения одного слова!!!
                                                                                                          // z1 - само слово
                                                                                                          // z2 - номер падежа
                                                                                                          // z3 - пол
                                                                                                          // z4 - 1-склонять как фамилию, 2-имя, 3-отчество
                                                                                                          Функция ПадежС(z1,Знач z2=2,Знач z3="*",z4=0) Экспорт
                                                                                                          	z5=Найти(z1,"-");
                                                                                                          	z6=?(z5=0,"","-"+ПадежС(Сред(z1,z5+1,СтрДлина(z1)-z5+1),z2,z3,z4));
                                                                                                          	z1=НРег(?(z5=0,z1,Лев(z1,z5-1)));
                                                                                                          	z7=Прав(z1,3);z8=Прав(z7,2);z9=Прав(z8,1);
                                                                                                          	z5=СтрДлина(z1);
                                                                                                          	za=Найти("ая ия ел ок яц ий па да ца ша ба та га ка",z8);
                                                                                                          	zb=Найти("аеёийоуэюяжнгхкчшщ",Лев(z7,1));
                                                                                                          	zc=Макс(z2,-z2);
                                                                                                          	zd=?(za=4,5,Найти("айяь",z9));
                                                                                                          	zd=?((zc=1)или(z9=".")или((z4=2)и(Найти("оиеу"+?(z3="ч","","бвгджзклмнпрстфхцчшщъ"),z9)>0))или((z4=1)и(Найти("мия мяэ лия кия жая лея",z7)>0)),9,?((zd=4)и(z3="ч"),2,?(z4=1,?(Найти("оеиую",z9)+Найти("их ых аа еа ёа иа оа уа ыа эа юа яа",z8)>0,9,?(z3<>"ч",?(za=1,7,?(z9="а",?(za>18,1,6),9)),?(((Найти("ой ый",z8)>0)и(z5>4)и(Найти("опой вбой",Прав(z1,4))=0))или((zb>10)и(za=16)),8,zd))),zd)));
                                                                                                          	ze=Найти("лец нёк вей бей дец пец мец нец рец вец аец иец ыец бер",z7);
                                                                                                          	zf=?((zd=8)и(zc<>5),?((zb>15)или(Найти("жий ний",z7)>0),"е","о"),?(z1="лев","ьв",?((Найти("аеёийоуэюя",Сред(z1,z5-3 ,1))=0)и((zb>11)или(zb=0))и(ze<>49),"",?(za=7,"л",?(za=10,"к",?(za=13,"йц",?(ze=0,"",?(ze<16,"ь"+?(ze=1,"ц",?(ze=5,"к","")),?(ze<41,"ц",?(ze<53,"йц","р"))))))))));
                                                                                                          	zf=?((zd=9)или((z4=3)и(Прав(z1,1)="ы")),z1,Лев(z1,z5-?((zd>6)или(zf<>""),2,?(zd>0,1,0)))+zf+СокрП(Сред("а у а "+?((z8="ич")или(z8="ыш"),"е",?((z8="ов")or(z8="ин"),"ы","о"))+"ме "+?(Найти("гжкхш",Лев(z8,1))>0,"и","ы")+" е у ойе я ю я ем"+?(za=16,"и","е")+" и е ю ейе и и ь ьюи и и ю ейи ойойу ойойойойуюойойгомуго"+?((zf="е")или(za=16)или((zb>12)и(zb<16)),"и","ы")+"мм",10*zd+2*zc-3,2)));
                                                                                                          	Возврат ?(""=z1,"",?(z4>0,ВРег(Лев(zf,1))+?((z2<0)и(z4>1),".",Сред(zf,2)),zf)+z6);
                                                                                                          КонецФункции
                                                                                                          
                                                                                                          //_____________________________________________________________________________
                                                                                                          // z1 - фамилия имя отчество например Железняков Юрий Юрьевич
                                                                                                          // z2 - Падеж ( по  умолчанию = 2 - родительный)
                                                                                                          // 2 - родительный  ( нет кого?    ) Железнякова Юрия Юрьевича
                                                                                                          // 3 - дательный    ( кому?        ) Железнякову Юрию Юрьевичу
                                                                                                          // 4 - винительный  ( вижу кого?   ) Железнякова Юрия Юрьевича
                                                                                                          // 5 - творительный ( кем?         ) Железняковым Юрием Юрьевичем
                                                                                                          // 6 - предложный   ( о ком?       ) Железнякове Юрии Юрьевиче
                                                                                                          // Если задать Z2 меньше 0, то на выходе получим от -1=Железняков Ю. Ю. до -6=Железнякове Ю. Ю.
                                                                                                          // z3 - параметр Пол может не указываться, но при наличии фамилий с
                                                                                                          // инициалами точное определение пола невозможно, поэтому предлагается задавать пол этим
                                                                                                          // параметром  1 - мужской 2 - женский
                                                                                                          // ДЛЯ СКЛОНЕНИЯ ПРОФЕССИЙ ИСПОЛЬЗУЙТЕ ФУНКЦИЮ ПАДЕЖП И БУДЕТ ВАМ СЧАСТЬЕ!
                                                                                                          // ---------------------------------------------------------------------------------------
                                                                                                          // Бибик Галушка Цой Николайчик Наталия Петровна Герценберг Кривошей Капица-Метелица
                                                                                                          // Если Падеж(Фио ,1 ,3),       то на выходе получим Фамилия Имя Отчество и т.д.
                                                                                                          // Если Падеж(Фио ,1 ,3,"1" ),  то                   Фамилия
                                                                                                          // Если Падеж(Фио ,1 ,3,"2" ),  то                   Имя
                                                                                                          // Если Падеж(Фио ,1 ,3,"3" ),  то                   Отчество
                                                                                                          // Если Падеж(Фио, 1 ,3,"12" ), то                   Фамилия Имя
                                                                                                          // Если Падеж(Фио, 1 ,3,"23" ), то                   Имя Отчество
                                                                                                          // Если Падеж(Фио,-1 ,3,"231" ),то                   И. О. Фамилия
                                                                                                          // Если Падеж(Фио,-1 ,3,"23" ), то                   И. О.
                                                                                                          // 10-11-2003 3-20
                                                                                                          Функция Падеж(z1,z2=2,z3=3,z4="123",z5=1) Экспорт
                                                                                                          	z6=Нрег(Прав(СокрП(z1),4));
                                                                                                          	z7=Прав(z6,1);
                                                                                                          	Возврат?(z5<4,Падеж(СокрЛП(СтрЗаменить(Сред(z1,Найти(z1+" "," ")+1),".",". ")),z2,z3,СтрЗаменить(z4,z5,ПадежС(?((z5=3)и(z7="ы"),z1,Лев(z1,Найти(z1+" "," ")-1)),z2,Сред("ча"+z7,?(z3=3,?(z6="оглы",1,?(z6="кызы",1,3)),z3),1),z5)+" "),z5+1),z4);
                                                                                                          КонецФункции
                                                                                                          
                                                                                                          Функция ПадежП(Знач z1,Знач z2,z3=0) Экспорт
                                                                                                          	z1=СокрЛП(z1);z4=Найти(z1+" "," ")+1;z5=Лев(z1,z4-2);z6=Прав(z5,2);
                                                                                                          	z7=?((Найти("ая ий ый",z6)>0)и(Найти("ющий нный",Сред(z1,z4-5,4))=0)и(z3=0),"1","*");
                                                                                                          	Возврат НРег(?((z6="ая")или(Прав(z6,1)="а"),ПадежС(z5,z2,z7,1)+" "+ПадежС(Сред(z1,z4),z2),ПадежС(z5,z2,"ч",1)+?((z6="ий")и(Найти(z1," ")=0),""," "+?(z7="1",ПадежП(Сред(z1,z4),z2,Число(z7)),Сред(z1,z4)))));
                                                                                                          КонецФункции
                                                                                                          
                                                                                                          
                                                                                                          
                                                                                                            0
                                                                                                            Блин, я был уверен, что я не слабонервный, но это… это…
                                                                                                            А-а-а-а-а!
                                                                                                            +1
                                                                                                            Имя «Павел» просклонял в творительном падеже как «Павелом».
                                                                                                              0
                                                                                                              Спасибо, исправим.
                                                                                                              +1
                                                                                                              В Python для подобных вещей давно использую pymorphy.
                                                                                                              Кстати, было бы гораздо интереснее, если бы описали в общих словах алгоритмы, на которых это всё основывается.
                                                                                                                +1
                                                                                                                Для определения пола есть отличный русский гем: russian_sex от makaroni4
                                                                                                                  +1
                                                                                                                  У меня получилось без особых проблем портировать библиотеку на javascript (nodejs). Работает с вашим набором правил yml.
                                                                                                                  > require('petrovich').firstname('Никита', 'male', 'dative');
                                                                                                                  Никите
                                                                                                                  > require('petrovich').middlename('Александрович', 'male', 'dative')
                                                                                                                  Александровичу
                                                                                                                  

                                                                                                                  Если это кому-нибудь нужно, проведу небольшой рефакторинг, оформлю в виде npm пакета, и, скорее всего, даже сделаю скрипт для браузеров, и выложу все это на github.
                                                                                                                  0
                                                                                                                  Отличная штука, портировал на JavaScript: http://github.com/deNULL/petrovich-js.

                                                                                                                  Для демо у вас страничку утащил, извините если что :)

                                                                                                                  Использовать можно примерно так:

                                                                                                                  <script src="lib/petrovich.js"></script>
                                                                                                                  <script src="lib/petrovich.rules.js"></script>
                                                                                                                  

                                                                                                                  // Можно сразу указать ФИО так...
                                                                                                                  var ivan = new Petrovich("Иванов", "Иван", "Иванович", Petrovich.MALE);
                                                                                                                  var ivanName = ivan.lastName(Petrovich.GENITIVE);
                                                                                                                  
                                                                                                                  // ...или так
                                                                                                                  var gadya = new Petrovich({ firstName: "Гадя", middleName: "Петрович", lastName: "Хренова" }, Petrovich.FEMALE);
                                                                                                                  
                                                                                                                  // Или не указывать вовсе, как в исходной либе (кстати, пол тоже опционален)
                                                                                                                  var petya = new Petrovich(Petrovich.ANDROGYNOUS);
                                                                                                                  var petyaName = petya.firstName("Петя", Petrovich.DATIVE);
                                                                                                                  
                                                                                                                  // А можно и вовсе не создавать объект
                                                                                                                  var otherName = Petrovich.lastName("Петров", Petrovich.ACCUSATIVE, Petrovich.MALE); 
                                                                                                                  
                                                                                                                    0
                                                                                                                    Класс. Добавим ссылку с нашего репо.
                                                                                                                      0
                                                                                                                      Упомянул этот порт на главной странице репозитория, спасибо за отличную работу. Мне кажется, вам стоит объединить усилия с MainNika.
                                                                                                                        0
                                                                                                                        Почему я попадаю на эмульгатор DCPU-16, когда жму Enter?
                                                                                                                        0
                                                                                                                        Начал портировать на .NET как и обещал, вечером дам ссылку на гитхаб. Пока что все просто в лоб переписал. Надо еще порефакторить и навести красоту
                                                                                                                          +1
                                                                                                                          eveel,Bonch, cсылка на гитхаб. Проект сыроват пока, но уже можно юзать. все работает. В ближайшее время добавлю тесты и все остальное.
                                                                                                                          0
                                                                                                                          Пожалуйста, обратите внимание, что оригинальный репозиторий переехал на новый адресgithub.com/petrovich/petrovich-ruby.

                                                                                                                          Теперь мы поддерживаем несколько официальных портов, список которых представлен на странице организации github.com/petrovich/petrovich.
                                                                                                                            0
                                                                                                                            А с правилами у вас всё правильно? Насколько я понимаю, они едины для всех портов. Тесты я взял из .net, проверил на php — не проходят 2 кейса. Если внимательно посмотреть на правила, они и не должны проходить, так как эти случаи в правилах попадают под исключения по андрогинам, а в тестах они подаются как female. А вот на демо-сайте с ruby всё обрабатывается правильно.

                                                                                                                            В общем, гляньте вот на это, тест из порта .net, файл src/NPetrovich.Tests/Data/LastNames.csv:

                                                                                                                            Джанджагава, Female, Dative, Джанджагава
                                                                                                                            Забейворота, Female, Dative, Забейворота


                                                                                                                            В php-порте получается «Джанджагаве» и «Забейвороте», другие порты просто не гонял пока.

                                                                                                                            (на самом деле я на перле порт набросал слегка, на коленке… пошёл по тестам — и наткнулся на непонятность)
                                                                                                                              0
                                                                                                                              Спасибо за комментарий!

                                                                                                                              Эталонным поведением считается поведение Ruby-версии библиотеки, так сложилось исторически. Имеется централизованный репозиторий с правилами, которые должны использоваться всеми портами. Если этого не происходит, то нужно обратиться к автору порта. Если выявляются ошибки в правилах, то мы стараемся исправить их по мере информирования.

                                                                                                                              Сейчас PHP-версия поддерживается difiso. Надеюсь, он увидит этот вопрос.
                                                                                                                                0
                                                                                                                                Скармливал PHP те же правила, значит, то-то не так в алгоритме. Написал на гите.

                                                                                                                                Насчёт перла пока не знаю. В принципе есть Lingua::RU::Inflect, который делает то же самое. Правда, не умеет двойные имена (Петров-Водкин будет склонять только по Водкин), но это решается просто. В остальном нужны тесты, много тестов, чтобы сравнить качество.
                                                                                                                            +1
                                                                                                                            Сравнение Lingua::RU::Inflect и набросанного на скорую руку перлового порта Петровича: тыц мышой. В таблицах подсвечены общие «провалы». Файл для теста — surnames.tsv отсюда. Общий счёт по ошибкам — 168:695 :) Хотя Петрович помедленней получается, но тут есть ещё что подкрутить.
                                                                                                                              +1
                                                                                                                              Похоже в Петровиче нужно правила подкорректировать. Посмотрел на тест — там вроде однотипные ошибки — фамилии оканчивающиеся на ке/ре/ом неправильно склоняются. Хотя фамилия Дюссар в вашем примере неправильно склоняется, но здесь — petrovich.rocketscience.it/ правильно. Странно.
                                                                                                                                0
                                                                                                                                Там ещё есть какие-то странные выпадения гласных: Вайншток => Вайнштка, Вайнштку, Вайнштком, о Вайнштке…
                                                                                                                                0
                                                                                                                                А почему пол задается через конструктор? По моему, не слишком удобно.

                                                                                                                                PS. Когда я что-то подобное писал, я не справился с двумя фамилиями акционеров АНТК Туполева — Заяц и Ручей.
                                                                                                                                  0
                                                                                                                                  Какие есть решения для определения имени в ФИО?

                                                                                                                                  Only users with full accounts can post comments. Log in, please.