Exemplo n.º 1
0
def inflect(morph, lastname, gram_form):
    '''
    Вернуть вариант фамилии который соотвествует данной грамматической
    форме

    Параметры:

    * morph - объект Morph
    * lastname - фамилия которую хотим склонять
    * gram_form - желаемые характеристики грам. формы (если u'жр' отсутствует
      в этом параметре, то по-умолчанию принимается u'мр', или u'мр-жр', если
      указано u'мн')
    '''

    expected_form = GramForm(gram_form)

    gender_tag = (u'мр-жр' if expected_form.match_string(u'мн') else None)
    if not gender_tag:
        gender_tag = (expected_form.match_string(u'жр') or u'мр')

    # За один проход проверяется, что исходное слово может быть склонено как
    # фамилия и выбирается форма подходящая под gram_form

    present_in_decline = False
    accepted = {}
    for item in decline(lastname):
        form = GramForm(item.get('info', u''))

        # Если в результате склонения не получилось исходной формы - ложное срабатывание

        # Обязательно проверяется род: при склонении в противоположном роде
        # может получиться исходная форма но нас интересует совпадение только в
        # заданном роде

        if item.get('word', '') == lastname:
            # В случае склонения во множественную форму, род игнорируется.
            # Род всех фамилий во множественном числе - мр-жр.
            if expected_form.match_string(u'мн') or form.match_string(gender_tag):
                present_in_decline = True

        expected = form.match(expected_form)

        if expected and not accepted:
            accepted = item
            # Здесь break не нужен т.к. present_in_decline всё ещё может быть
            # не установлена в корректное значение

    # Если в результате склонения исходной формы не получилось,
    # возвращается результат склонения как для обычного слова

    if present_in_decline and accepted:
        return accepted.get('word', u'')
    else:
        return morph.inflect_ru(lastname, gram_form, smart_guess=False)
Exemplo n.º 2
0
 def is_correct(frm):
     correct = True
     if norm:
         correct = frm['norm'] == norm
     if method:
         correct = correct and (method in frm['method'])
     if cls:
         correct = correct and (frm['class'] == cls)
     if form:
         gram_filter = GramForm(form)
         gram_form = GramForm(frm['info'])
         correct = correct and gram_form.match(gram_filter)
     return correct
Exemplo n.º 3
0
 def is_correct(frm):
     correct = True
     if norm:
         correct = frm['norm'] == norm
     if method:
         correct = correct and (method in frm['method'])
     if cls:
         correct = correct and (frm['class'] == cls)
     if form:
         gram_filter = GramForm(form)
         gram_form = GramForm(frm['info'])
         correct = correct and gram_form.match(gram_filter)
     return correct
Exemplo n.º 4
0
 def test_match_inverted(self):
     form = GramForm("мр,ед,имя")
     self.assertFalse(form.match(GramForm("мр,!имя")))
     self.assertTrue(form.match(GramForm("ед,!тв")))
Exemplo n.º 5
0
 def test_match(self):
     form = GramForm("мр,ед,имя")
     self.assertTrue(form.match(GramForm("мр")))
     self.assertTrue(form.match(GramForm("ед,мр")))
Exemplo n.º 6
0
def decline(lastname, gram_form=u''):
    ''' Склоняет фамилию и возвращает все возможные формы '''

    # Из фамилии выделяется предполагаемая лемма (Табуретов -> Табуретов,
    # Табуретовым -> Табуретов), лемма склоняется по правилам склонения фамилий

    def guess_lemma(name):
        '''
        Попытаться угадать сложносклоняемую фамилию (Цапок, Бегунец, Берия)

        Возвращает пару (name=lemma+suffix, lemma) либо (None, None)
        '''

        name_len = len(name)

        # Попытка угадать склонённую фамилию из 13.1.12 ("Берией")
        if name_len > 2 and name[-2:] in (u'ИИ', u'ИЮ',):
            return (lastname[:-2] + u'ИЯ', lastname[:-2])
        elif name_len > 3 and name[-3:] in (u'ИЕЙ',):
            return (lastname[:-3] + u'ИЯ', lastname[:-3])

        # Попытка угадать склонённую фамилию, закачивающуюся на -ок ("Цапка")
        # Работает, только если буква перед окончанием согласная.
        # Проверка согласной делается для исключения склонённых фамилий на -ак
        # ("Собчака")
        if name_len > 3 and name[-2:] in (u'КА', u'КУ', u'КЕ',) and name[-3] in CONSONANTS:
            return (lastname[:-2] + u'ОК', lastname[:-2])
        elif name_len > 4 and name[-3:] in (u'КОМ',) and name[-4] in CONSONANTS:
            return (lastname[:-3] + u'ОК', lastname[:-3])

        # Попытка угадать склонённую фамилию, закачивающуюся на -ец ("Бегунец")
        # FIXME: необходима проверка на коллизии с другими фамилиями (как в
        # случае с "Цапок")
        if name_len > 3 and name[-2:] in (u'ЦА', u'ЦУ', u'ЦЕ',):
            return (lastname[:-2] + u'ЕЦ', lastname[:-2])

        return (None, None)


    match = LASTNAME_PATTERN.search(lastname)
    lemma = name = match.group(1) if match else lastname # name is lemma + suffix
    name_len = len(name)

    guessed_name, guessed_lemma = guess_lemma(name)
    if guessed_name and guessed_lemma:
        name, lemma = guessed_name, guessed_lemma

    cases, plural_cases = {}, ()
    if name_len > 2:
        cases, plural_cases = CASEMAP.get(name[-2:], ({}, ()))
        if cases:
            lemma = name[:-2]

    if not cases and name_len > 3:
        cases, plural_cases = CASEMAP.get(name[-3:], ({}, ()))
        if cases:
            lemma = name[:-3]

    # В случае 13.1.12 лемма состоит из фамилии, за исключением
    # двух последних букв
    if cases is CASES_IA or cases is CASES_OK:
        lemma = name = name[:-2]

    if not cases:
        return []

    expected_form = GramForm(gram_form)

    forms = []
    for i, case in zip(xrange(6), (u'им', u'рд', u'дт', u'вн', u'тв', u'пр',)):
        for gender_tag in (u'мр', u'жр',):
            form = GramForm(u'%s,%s,фам,ед' % (case, gender_tag,))

            if gram_form and not form.match(expected_form):
                continue

            forms.append({
                'word': u'%s%s' % (name, cases[gender_tag][i]),
                'class': u'С',
                'info': form.get_form_string(),
                'lemma': name,
                'method': u'decline_lastname (%s)' % lastname,
                'norm': u'%s%s' % (name, cases[gender_tag][0]),
            })

        plural_form = GramForm(u'%s,мр-жр,фам,мн' % (case,))

        if gram_form and not plural_form.match(expected_form):
            continue

        forms.append({
            'word': u'%s%s' % (name, plural_cases[i]),
            'class': u'С',
            'info': plural_form.get_form_string(),
            'lemma': name,
            'method': u'decline_lastname (%s)' % lastname,
            'norm': u'%s%s' % (name, plural_cases[0]),
        })

    # Просклонять рекурсивно для случая с множественным числом фамилии.
    # Козловых -> фам,им; Козловых (мн) -> Козлов -> фам,им
    if lemma != name and LASTNAME_PATTERN.match(lemma):
        refinement = decline(lemma)
        if refinement:
            return forms + refinement

    return forms
Exemplo n.º 7
0
 def test_match_inverted(self):
     form = GramForm(u"мр,ед,имя")
     self.assertFalse(form.match(GramForm(u"мр,!имя")))
     self.assertTrue(form.match(GramForm(u"ед,!тв")))
Exemplo n.º 8
0
 def test_match(self):
     form = GramForm(u"мр,ед,имя")
     self.assertTrue(form.match(GramForm(u"мр")))
     self.assertTrue(form.match(GramForm(u"ед,мр")))