def loc_case(func, i): # Местный падеж r = i.result # local if _.contains(i.index, 'П2') or _.contains(i.index, 'П₂'): loc = r['dat-sg'] # local loc = _.replaced(loc, '́ ', '') loc = _.replaced(loc, 'ё', 'е') loc = _.replaced(loc, '({vowel})({consonant}*)$', '%1́ %2') loc = remove_stress_if_one_syllable(loc) # = export. r['loc-sg'] = loc loc_prep = _.extract(i.index, 'П2%((.+)%)') # local if not loc_prep: loc_prep = _.extract(i.index, 'П₂%((.+)%)') # end if not loc_prep: loc_prep = 'в, на' # end r['loc-sg'] = '(' + loc_prep + ') ' + r['loc-sg'] if _.contains(i.index, '%[П'): r['loc-sg'] = r['loc-sg'] + ' //<br />' + r['prp-sg'] # end # end if _.has_value(i.args, 'М'): r['loc-sg'] = i.args['М'] # end _.ends(module, func)
def generate_result(func, i): # export r = i.result # local init_forms.init_forms(i) if i.adj: init_forms.init_srt_forms(i) # end _.log_table(r, 'i.result') common_forms.fix_stress(i) if i.adj and i.calc_pl: # `calc_pl` -- чтобы считать их только один раз, а не для каждого рода adj_forms.add_comparative(i) # end for key, value in r.items(): # replace 'ё' with 'е' when unstressed # if _.contains_once(i.stem.unstressed, 'ё') and _.contains(value, '́ ') and _.contains(i.rest_index, 'ё'): -- trying to bug-fix if _.contains_once(value, 'ё') and _.contains(value, '́ ') and _.contains(i.rest_index, 'ё'): if i.adj and _.contains(i.stress_type, "a'") and i.gender == 'f' and key == 'srt-sg': r[key] = _.replaced(value, 'ё', 'е') + ' // ' + _.replaced(value, '́', '') else: r[key] = _.replaced(value, 'ё', 'е') # обычный случай # end # end # end if i.noun: noun_forms.apply_obelus(i) # end common_forms.choose_accusative_forms(i) common_forms.second_ins_case(i) if i.noun: noun_forms.apply_specific_3(i) # end for key, value in r.items(): # INFO Удаляем ударение, если только один слог: r[key] = noun_forms.remove_stress_if_one_syllable(value) # end if i.adj: if i.postfix: # local keys keys = [ 'nom-sg', 'gen-sg', 'dat-sg', 'acc-sg', 'ins-sg', 'prp-sg', 'nom-pl', 'gen-pl', 'dat-pl', 'acc-pl', 'ins-pl', 'prp-pl', ] # list for j, key in enumerate(keys): r[key] = r[key] + 'ся' # end # end # end _.ends(module, func)
def process(func, i): # export _.log_info('Извлечение информации об ударении (stress_type)') stress.extract_stress_type(i) # todo: move to `parse` _.log_value(i.stress_type, 'i.stress_type') if e.has_error(i): return _.returns(module, func, i) # end if not i.stress_type: # если ударение не указано if _.contains(i.rest_index, '0'): # если несклоняемая схема i.stress_type = '' else: # INFO: Если при этом есть какой-то индекс, это явно ОШИБКА if _.has_value(i.rest_index): e.add_error(i, 'Нераспознанная часть индекса: ' + i.rest_index) return _.returns(module, func, i) # end # INFO: Если же индекса вообще нет, то и формы просто не известны: i.has_index = False return _.returns(module, func, i) # end # end _.log_info('Вычисление схемы ударения') stress.get_stress_schema(i) _.log_info('Определение типа основы (stem_type)') stem_type.get_stem_type(i) _.log_value(i.stem.type, 'i.stem.type') _.log_value(i.stem.base_type, 'i.stem.base_type') # INFO: Итак, ударение мы получили. # INFO: Добавление ударения для `stem.stressed` (если его не было) # INFO: Например, в слове только один слог, или ударение было на окончание if not _.contains(i.stem.stressed, '[́ ё]'): # and not i.absent_stress ?? if _.equals(i.stress_type, ["f", "f'"]): i.stem.stressed = _.replaced(i.stem.stressed, '^({consonant}*)({vowel})', '%1%2́ ') elif _.contains(i.rest_index, '%*'): pass # *** поставим ударение позже, после чередования else: i.stem.stressed = _.replaced(i.stem.stressed, '({vowel})({consonant}*)$', '%1́ %2') # end # end _.log_value(i.stem.stressed, 'i.stem.stressed') _.log_info('Инициализируем `i.result`') init_result.init_result(i) return _.returns(module, func, i)
def apply_specific_3(func, i): # export r = i.result # local # Специфика по (3) if _.contains(i.rest_index, '%(3%)') or _.contains(i.rest_index, '③'): if _.endswith(r['prp-sg'], 'и'): r['prp-sg'] = r['prp-sg'] + ' //<br />' + _.replaced(r['prp-sg'], 'и$', 'е') # end if i.gender == 'f' and _.endswith(r['dat-sg'], 'и'): r['dat-sg'] = r['dat-sg'] + ' //<br />' + _.replaced(r['dat-sg'], 'и$', 'е') # end # end _.ends(module, func)
def extract_stress_type(func, i): # export # OLD: Старая версия кода: # # local stress_regexp = "([abcdef][′']?[′']?)" # # local stress_regexp2 = '(' + stress_regexp + '.*//.*' + stress_regexp + ')' # stress_regexp = '(' + stress_regexp + '(% ?.*))' # i.stress_type = _.extract(i.rest_index, stress_regexp2) # if not i.stress_type: # i.stress_type = _.extract(i.rest_index, stress_regexp) # # end # local stress_type, allowed_stress_types # INFO: Извлечение ударения из оставшейся части индекса: i.stress_type = _.extract(i.rest_index, "([abcdef][′']?[′']?[/]?[abc]?[′']?[′']?)") # INFO: Замена особых апострофов в ударении на обычные: if i.stress_type: i.stress_type = _.replaced(i.stress_type, '′', "'") # end # INFO: Список допустимых схем ударений: allowed_stress_types = { # todo: special variables for that? 'a', "a'", 'b', "b'", 'c', 'd', "d'", 'e', 'f', "f'", "f''", 'a/a', 'a/b', 'a/c', "a/a'", "a/b'", "a/c'", "a/c''", 'b/a', 'b/b', 'b/c', "b/a'", "b/b'", "b/c'", "b/c''", } # INFO: Если ударение есть и оно не из допустимого списка -- это ошибка if i.stress_type and not _.equals(i.stress_type, allowed_stress_types): e.add_error(i, 'Ошибка: Неправильная схема ударения: ' + i.stress_type) # end _.ends(module, func)
def init_stem(func, i): # export # todo rename to `init_stem` # INFO: Исходное слово без ударения: i.word.unstressed = _.replaced(i.word.stressed, '́ ', '') # todo: move outside this function # INFO: Исходное слово вообще без ударений (в т.ч. без грависа): i.word.cleared = _.replaced( _.replaced(_.replaced(i.word.unstressed, '̀', ''), 'ѐ', 'е'), 'ѝ', 'и') if i.adj: if _.endswith(i.word.stressed, 'ся'): i.postfix = True i.stem.unstressed = _.replaced(i.word.unstressed, '{vowel}[йяе]ся$', '') i.stem.stressed = _.replaced(i.word.stressed, '{vowel}́ ?[йяе]ся$', '') else: i.stem.unstressed = _.replaced(i.word.unstressed, '{vowel}[йяе]$', '') i.stem.stressed = _.replaced(i.word.stressed, '{vowel}́ ?[йяе]$', '') # end else: # INFO: Удаляем окончания (-а, -е, -ё, -о, -я, -й, -ь), чтобы получить основу: i.stem.unstressed = _.replaced(i.word.unstressed, '[аеёийоьыя]$', '') i.stem.stressed = _.replaced(i.word.stressed, '[аеёийоьыя]́ ?$', '') # end _.log_value(i.word.unstressed, 'i.word.unstressed') _.log_value(i.stem.unstressed, 'i.stem.unstressed') _.log_value(i.stem.stressed, 'i.stem.stressed') # INFO: Случай, когда не указано ударение у слова: several_vowels = _.contains_several(i.word.stressed, '{vowel+ё}') # local has_stress = _.contains(i.word.stressed, '[́ ё]') # local if several_vowels and not has_stress: _.log_info('Ошибка: Не указано ударение в слове') e.add_error(i, 'Ошибка: Не указано ударение в слове') i.result.error_category = 'Ошибка в шаблоне "сущ-ru" (не указано ударение в слове)' # end _.ends(module, func)
def add_comparative(func, i): # export # todo: move to `modify` (и сделать через основы и окончания) r = i.result # local if _.contains(i.rest_index, '~'): r['comparative'] = '-' return _.ends(module, func) # end if i.stem.type == '3-velar': new_stem = i.stem.unstressed if _.endswith(new_stem, 'к'): new_stem = _.replaced(new_stem, 'к$', 'ч') elif _.endswith(new_stem, 'г'): new_stem = _.replaced(new_stem, 'г$', 'ж') elif _.endswith(new_stem, 'х'): new_stem = _.replaced(new_stem, 'х$', 'ш') else: pass # todo: some error here # end # ударение на предпоследний слог: new_stem = _.replaced(new_stem, '({vowel})({consonant}*)$', '%1́ %2') r['comparative'] = new_stem + 'е' else: if _.contains(i.rest_index, ['%(2%)', '②']): # todo: special variable for this r['comparative'] = i.parts.stems['nom-pl'] + 'ее' r['comparative2'] = i.parts.stems['nom-pl'] + 'ей' else: if _.equals(i.stress_type, ['a', 'a/a']): r['comparative'] = i.stem.stressed + 'ее' r['comparative2'] = i.stem.stressed + 'ей' else: r['comparative'] = i.stem.unstressed + 'е́е' r['comparative2'] = i.stem.unstressed + 'е́й' # end # end # end _.ends(module, func)
def second_ins_case(func, i): # export r = i.result # local # Второй творительный if i.gender == 'f' and i.calc_sg: ins_sg2 = _.replaced(r['ins-sg'], 'й$', 'ю') # local if ins_sg2 != r['ins-sg']: _.log_info( 'Замена "й" на "ю" для второго творительного женского рода') r['ins-sg2'] = ins_sg2 # end # end _.ends(module, func)
def transform(func, i): # export # local stem_stress_schema p = i.parts # local # apply special cases (1) or (2) in index if i.adj: adj_circles.apply_adj_specific_1_2(i) # end # *** для случая с расстановкой ударения (см. ниже) # # local orig_stem = i.stem.unstressed # if _.contains(i.rest_index, ['%(2%)', '②']): # orig_stem = _.replaced(p.stems['gen-pl'], '́ ', '') -- удаляем ударение для случая "сапожок *d(2)" # mw.log('> Another `orig_stem`: ' + str(orig_stem)) # # end # reducable i.rest_index = degree.apply_specific_degree(i) reducable.apply_specific_reducable(i, i.gender, i.rest_index, False) if not _.equals(i.stress_type, ["f", "f'"]) and _.contains( i.rest_index, '%*'): _.log_info( 'Обработка случая на препоследний слог основы при чередовании') orig_stem = i.stem.unstressed if i.forced_stem: orig_stem = i.forced_stem # end for key, stem in p.stems.items(): # mw.log(' - ' + key + ' -> ' + stem) # mw.log('Ударение на основу?') # mw.log(i.stress_schema['stem'][key]) stem_stress_schema = i.stress_schema['stem'] if not _.contains(stem, '[́ ё]') and _.has_key( stem_stress_schema, key) and stem_stress_schema[key]: # *** случай с расстановкой ударения (см. выше) # "Дополнительные правила об ударении", стр. 34 old_value = p.stems[key] # mw.log('> ' + key + ' (old): ' + str(old_value)) if p.stems[ key] != orig_stem: # попытка обработать наличие беглой гласной (не знаю, сработает ли всегда) p.stems[key] = _.replaced( stem, '({vowel})({consonant}*)({vowel})({consonant}*)$', '%1́ %2%3%4') if not _.contains( p.stems[key], '[́ ё]'): # если предпоследнего слога попросту нет # сделаем хоть последний ударным p.stems[key] = _.replaced(stem, '({vowel})({consonant}*)$', '%1́ %2') # end else: p.stems[key] = _.replaced(stem, '({vowel})({consonant}*)$', '%1́ %2') # end # mw.log('> ' + key + ' (new): ' + str(p.stems[key])) mw.log(' - ' + key + ': "' + str(old_value) + '" -> "' + str(p.stems[key]) + '"') # end # end # end if i.calc_pl: # Специфика по "ё" if _.contains(i.rest_index, 'ё') and not _.contains( p.endings['gen-pl'], '{vowel+ё}') and not _.contains( p.stems['gen-pl'], 'ё'): p.stems['gen-pl'] = _.replaced(p.stems['gen-pl'], 'е́?([^е]*)$', 'ё%1') i.rest_index = i.rest_index + 'ё' # ??? # end # end _.ends(module, func)
def remove_stress_if_one_syllable(value): # export if _.contains_once(value, '{vowel+ё}'): return _.replaced(value, '́ ', '') # end return value
def extract_gender_animacy(func, i): # export # local convert_animacy, orig_index, rest_index # мо-жо - mf a # ж//жо - f ina//a # мо - m a # с - n ina i.pt = False if _.startswith(i.index, 'п'): i.adj = True elif _.extract(i.index, '^м//ж') or _.extract( i.index, '^m//f'): # todo: INFO: похоже все такие случаи либо 0, либо <...> i.gender = 'mf' i.animacy = 'in' elif _.extract(i.index, '^м//с') or _.extract(i.index, '^m//n'): i.gender = 'mn' i.animacy = 'in' elif _.extract(i.index, '^ж//м') or _.extract(i.index, '^f//m'): i.gender = 'fm' i.animacy = 'in' elif _.extract(i.index, '^ж//с') or _.extract(i.index, '^f//n'): i.gender = 'fn' i.animacy = 'in' elif _.extract(i.index, '^с//м') or _.extract(i.index, '^n//m'): i.gender = 'nm' i.animacy = 'in' elif _.extract(i.index, '^с//ж') or _.extract(i.index, '^n//m'): i.gender = 'nm' i.animacy = 'in' elif _.extract(i.index, '^мо%-жо') or _.extract(i.index, '^mf a'): i.gender = 'f' i.animacy = 'an' i.common_gender = True elif _.extract(i.index, '^мн'): i.gender = '' i.animacy = '' i.common_gender = False i.pt = True if _.extract(i.index, 'одуш'): i.animacy = 'an' elif _.extract(i.index, 'неод'): i.animacy = 'in' # end # TODO: Также удалить это ниже для rest_index, аналогично как удаляется м, мо и т.п. i.rest_index = i.index elif _.extract(i.index, '^мс'): i.pronoun = True elif _.extract( i.index, '^м' ): # fixme: сюда частично попадает необрабатываемый пока "м//мн." i.gender = 'm' i.animacy = get_cyrl_animacy(i.index, 'м') i.common_gender = False elif _.extract(i.index, '^ж'): i.gender = 'f' i.animacy = get_cyrl_animacy(i.index, 'ж') i.common_gender = False elif _.extract(i.index, '^с'): i.gender = 'n' i.animacy = get_cyrl_animacy(i.index, 'с') i.common_gender = False else: i.gender = _.extract(i.index, '^([mnf])') i.animacy = _.extract(i.index, '^[mnf] ([a-z/]+)') i.common_gender = False if i.animacy: convert_animacy = {} convert_animacy['in'] = 'in' convert_animacy['an'] = 'an' convert_animacy['ina'] = 'in' convert_animacy['a'] = 'an' convert_animacy['a//ina'] = 'an//in' convert_animacy['ina//a'] = 'in//an' convert_animacy['anin'] = 'an//in' convert_animacy['inan'] = 'in//an' i.animacy = convert_animacy[i.animacy] # end # end # Удаляем теперь соответствующий кусок индекса if (i.gender or i.gender == '') and i.animacy and not i.adj and not i.pronoun: _.log_value(i.index, 'i.index') orig_index = mw.text.trim(i.index) # # local test1 = _.replaced(i.index, '^mf a ?', '') # mw.log('test1 = ' + mw.text.trim(test1)) # # # local test2 = _.replaced(i.index, '^mf a ', '') # mw.log('test2 = ' + mw.text.trim(test2)) # # # local test3 = _.replaced(i.index, 'mf a ', '') # mw.log('test3 = ' + mw.text.trim(test3)) # # # local test4 = _.replaced(i.index, 'mf a', '') # mw.log('test4 = ' + mw.text.trim(test4)) # # # local test5 = mw.text.trim(_.replaced(i.index, '^mf a ?', '')) # mw.log('test5 = ' + test5) # # # local test6 = _.replaced(i.index, '^mf a ?', '') # mw.log('test6 = ' + test6) # # local test7 = mw.text.trim(test6) # mw.log('test7 = ' + test7) # TODO: Simplify things a bit here (сделать циклом!): rest_index = _.replaced(i.index, '^mf a ?', '') if rest_index != orig_index: i.rest_index = mw.text.trim(rest_index) _.log_info('Удаление "mf a" из индекса') _.log_value(i.rest_index, 'i.rest_index') return _.ends(module, func) # end rest_index = _.replaced(i.index, '^[mnf]+ [a-z/]+ ?', '') if rest_index != orig_index: i.rest_index = mw.text.trim(rest_index) _.log_info('Удаление "[mnf] [in/an]" из индекса') _.log_value(i.rest_index, 'i.rest_index') return _.ends(module, func) # end rest_index = _.replaced(i.index, '^мн%.? неод%.? ?', '') if rest_index != orig_index: i.rest_index = mw.text.trim(rest_index) _.log_info('Удаление "мн. неод." из индекса') _.log_value(i.rest_index, 'i.rest_index') return _.ends(module, func) # end rest_index = _.replaced(i.index, '^мн%.? одуш%.? ?', '') if rest_index != orig_index: i.rest_index = mw.text.trim(rest_index) _.log_info('Удаление "мн. одуш." из индекса') _.log_value(i.rest_index, 'i.rest_index') return _.ends(module, func) # end rest_index = _.replaced(i.index, '^мн%.? ?', '') if rest_index != orig_index: i.rest_index = mw.text.trim(rest_index) _.log_info('Удаление "мн." из индекса') _.log_value(i.rest_index, 'i.rest_index') return _.ends(module, func) # end rest_index = _.replaced( i.index, '^[-мжсо/]+%,? ?', '') # fixme: сюда частично попадает необрабатываемый пока "м//мн." if rest_index != orig_index: i.rest_index = mw.text.trim(rest_index) _.log_info('Удаление "м/ж/с/мо/жо/со/..." из индекса') _.log_value(i.rest_index, 'i.rest_index') return _.ends(module, func) # end e.add_error(i, 'TODO: process such errors') return _.ends(module, func) elif i.adj: _.log_value(i.index, 'i.index (п)') orig_index = mw.text.trim(i.index) rest_index = _.replaced(i.index, '^п ?', '') if rest_index != orig_index: i.rest_index = mw.text.trim(rest_index) _.log_info('Удаление "п" из индекса') _.log_value(i.rest_index, 'i.rest_index') return _.ends(module, func) # end elif i.pronoun: _.log_value(i.index, 'i.index (мс)') orig_index = mw.text.trim(i.index) rest_index = _.replaced(i.index, '^мс ?', '') if rest_index != orig_index: i.rest_index = mw.text.trim(rest_index) _.log_info('Удаление "мс" из индекса') _.log_value(i.rest_index, 'i.rest_index') return _.ends(module, func) # end # end _.ends(module, func)
def get_zaliznyak(func, i): # export # TODO: process <...> cases properly # also e.g. "2*a + <п 1a>" r = i.result # local if not i.has_index: r['зализняк1'] = '??' return _.ends(module, func) # end # local stem_types stem_types = { '1-hard': '1', '2-soft': '2', '3-velar': '3', '4-sibilant': '4', '5-letter-ц': '5', '6-vowel': '6', '7-letter-и': '7', '8-third': '8', } index = '?' # local if _.contains(i.rest_index, '0'): index = '0' else: # index = i.stem.type[0] -- TODO index = stem_types[i.stem.type] # end if _.contains(i.rest_index, '°'): index = index + '°' elif _.contains(i.rest_index, '%*'): index = index + '*' # end index = index + _.replaced(i.stress_type, "'", "'") if _.contains(i.rest_index, ['⊠', '%(x%)', '%(х%)', '%(X%)', '%(Х%)']): index = index + '⊠' elif _.contains(i.rest_index, ['✕', '×', 'x', 'х', 'X', 'Х']): index = index + '✕' # end if _.contains(i.rest_index, ['%(1%)', '①']): index = index + '①' # end if _.contains(i.rest_index, ['%(2%)', '②']): index = index + '②' # end if _.contains(i.rest_index, ['%(3%)', '③']): index = index + '③' # end if _.contains(i.rest_index, '÷'): index = index + '÷' # end if _.contains(i.rest_index, ['%-', '—', '−']): index = index + '−' # end if _.contains(i.rest_index, 'ё'): index = index + ', ё' # end r['зализняк1'] = index value = r['зализняк1'] # local # for category value = _.replaced(value, '①', '(1)') value = _.replaced(value, '②', '(2)') value = _.replaced(value, '③', '(3)') r['зализняк'] = value _.ends(module, func)