def test_match_string(self): form = GramForm("мр,ед,им") self.assertEqual(form.match_string("мр"), "мр") self.assertEqual(form.match_string("ед"), "ед") self.assertEqual(form.match_string("им"), "им") self.assertEqual(form.match_string("!имя"), "!имя") self.assertFalse(form.match_string("жр"))
def test_multi_form_change(self): form = GramForm(u'мн,рд,мр') form.update(u'дт,ед') self.assertTrue(u'дт' in form.form) self.assertTrue(u'ед' in form.form) self.assertFalse(u'рд' in form.form) self.assertFalse(u'мн' in form.form)
def test_match_string(self): form = GramForm(u'мр,ед,им') self.assertEqual(form.match_string(u'мр'), u'мр') self.assertEqual(form.match_string(u'ед'), u'ед') self.assertEqual(form.match_string(u'им'), u'им') self.assertEqual(form.match_string(u'!имя'), u'!имя') self.assertFalse(form.match_string(u'жр'))
def test_multi_form_change(self): form = GramForm("мн,рд,мр") form.update("дт,ед") self.assertTrue("дт" in form.form) self.assertTrue("ед" in form.form) self.assertFalse("рд" in form.form) self.assertFalse("мн" in form.form)
def test_form_str(self): form = GramForm(u'мр,мн,рд') self.assertTrue(form.get_form_string().count(u'мр') == 1) self.assertTrue(form.get_form_string().count(u'мн') == 1) self.assertTrue(form.get_form_string().count(u'рд') == 1) self.assertTrue(len(form.get_form_string()) == (2 * 3) + 2) form.update(u'дт') self.assertTrue(form.get_form_string().count(u'мр') == 1) self.assertTrue(form.get_form_string().count(u'мн') == 1) self.assertTrue(form.get_form_string().count(u'дт') == 1) self.assertTrue(len(form.get_form_string()) == (2 * 3) + 2)
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
def test_form_str(self): form = GramForm("мр,мн,рд") self.assertTrue(form.get_form_string().count("мр") == 1) self.assertTrue(form.get_form_string().count("мн") == 1) self.assertTrue(form.get_form_string().count("рд") == 1) self.assertTrue(len(form.get_form_string()) == (2 * 3) + 2) form.update("дт") self.assertTrue(form.get_form_string().count("мр") == 1) self.assertTrue(form.get_form_string().count("мн") == 1) self.assertTrue(form.get_form_string().count("дт") == 1) self.assertTrue(len(form.get_form_string()) == (2 * 3) + 2)
def test_form_str(self): form = GramForm(u'мр,мн,рд') self.assertTrue(form.get_form_string().count(u'мр') == 1) self.assertTrue(form.get_form_string().count(u'мн') == 1) self.assertTrue(form.get_form_string().count(u'рд') == 1) self.assertTrue(len(form.get_form_string()) == (2*3)+2) form.update(u'дт') self.assertTrue(form.get_form_string().count(u'мр') == 1) self.assertTrue(form.get_form_string().count(u'мн') == 1) self.assertTrue(form.get_form_string().count(u'дт') == 1) self.assertTrue(len(form.get_form_string()) == (2*3)+2)
def normalize(morph, lastname, hints=u''): ''' Возвращает нормальную форму (именительный падеж) фамилии для заданного рода Параметры: * hints - подсказки об исходной форме фамилии (u'мр' или u'жр', по-умолчанию принимается u'мр') ''' hints_form = GramForm(hints) gender_tag = (hints_form.match_string(u'жр') or u'мр') # FIXME: эта функция возвращает саму форму, а Morph.normalize возвращает # множество (set) возможных форм, одно из двух лучше поправить. return inflect(morph, lastname, u'им,ед,%s' % gender_tag)
def test_lemma_graminfo(self): info = morph_ru.get_graminfo(u'СУСЛИКАМИ') self.assertEqual(len(info), 1) info = info[0] gram_form = GramForm(info['info']) self.assertEqual(gram_form.form, set([u'мр', u'тв', u'мн'])) self.assertEqual(info['norm'], u'СУСЛИК')
def pluralize_inflected(morph, lastname, num, hints=u''): ''' Вернуть фамилию в форме, которая будет сочетаться с переданным числом. Например: 1 Попугаев, 2 Попугаевых, 5 Попугаевых. Параметры: * morph - объект Morph * lastname - фамилия которую хотим склонять * num - число * hints - подсказки об исходной форме фамилии (u'мр' или u'жр') ''' if num == 1: return normalize(morph, lastname, hints) hints_form = GramForm(hints) gender_tag = (hints_form.match_string(u'жр') or u'мр') return pluralize(morph, lastname, u'мн,рд,%s' % gender_tag)
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)
def pluralize(morph, lastname, gram_form=u''): ''' Вернуть фамилию во множественном числе. Параметры: * morph - объект Morph * lastname - фамилия которую хотим склонять * gram_form - желаемые характеристики грам. формы ''' expected_form = GramForm(gram_form) # Удалить из желаемой формы признаки рода и числа refined_form = GramForm(gram_form).clear_gender().clear_number() # Если дан gram_form - склонить в указанную форму if refined_form.get_form_string(): return inflect( morph, lastname, u','.join((refined_form.get_form_string(), u'мн',))) # Иначе - найти форму исходной фамилии и склонить в неё же, но во мн. числе # Если в желаемой форме был указан род - использовать как подсказку gender_tag = (expected_form.match_string(u'жр') or u'мр') for item in decline(lastname): form = GramForm(item.get('info', u'')) # Проверить наличие исходной формы в заданном роде (аналогично inflect()) if item.get('word', u'') == lastname and form.match_string(gender_tag): for case in (u'им', u'рд', u'дт', u'вн', u'тв', u'пр'): if form.match_string(case): return inflect(morph, lastname, u'мн,%s' % case) # В случае неудачи - просклонять как обычное слово return morph.pluralize_ru(lastname, gram_form)
def test_match(self): form = GramForm(u"мр,ед,имя") self.assertTrue(form.match(GramForm(u"мр"))) self.assertTrue(form.match(GramForm(u"ед,мр")))
def test_match_inverted(self): form = GramForm("мр,ед,имя") self.assertFalse(form.match(GramForm("мр,!имя"))) self.assertTrue(form.match(GramForm("ед,!тв")))
def test_match(self): form = GramForm("мр,ед,имя") self.assertTrue(form.match(GramForm("мр"))) self.assertTrue(form.match(GramForm("ед,мр")))
def test_from_str(self): form = GramForm(u'мн,рд') self.assertTrue(u'рд' in form.form) self.assertTrue(u'мн' in form.form)
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
def test_match_inverted(self): form = GramForm(u"мр,ед,имя") self.assertFalse(form.match(GramForm(u"мр,!имя"))) self.assertTrue(form.match(GramForm(u"ед,!тв")))