def init_result(func, i): # export r = i.result # local r['stem_type'] = i.stem.type # for testcases r['stress_type'] = i.stress_type # for categories -- is really used? r['dev'] = dev_prefix index.get_zaliznyak(i) additional_arguments(i) if i.noun: forward_gender_animacy(i) # end if i.adj: if _.contains(i.rest_index, ['⊠', '%(x%)', '%(х%)', '%(X%)', '%(Х%)']): r['краткая'] = '⊠' elif _.contains(i.rest_index, ['✕', '×', 'x', 'х', 'X', 'Х']): r['краткая'] = '✕' elif _.contains(i.rest_index, ['%-', '—', '−']): r['краткая'] = '−' else: r['краткая'] = '1' # end # end if not _.has_key(r, 'error_category') and i.word.cleared != i.base: r['error_category'] = 'Ошибка в шаблоне "сущ-ru" (слово не совпадает с заголовком статьи)' # end forward.forward_args(i) _.ends(module, func)
def apply_adj_specific_1_2(func, i): # export p = i.parts # local if i.calc_sg: if not _.endswith(p.stems['srt-sg'], 'нн'): # todo: log some error? return _.ends(module, func) # end if _.contains(i.rest_index, ['%(1%)', '①']): if i.gender == 'm': _.replace(p.stems, 'srt-sg', 'нн$', 'н') # end # end # end if _.contains(i.rest_index, ['%(2%)', '②']): if i.calc_sg: _.replace(p.stems, 'srt-sg', 'нн$', 'н') # end if i.calc_pl: _.replace(p.stems, 'srt-pl', 'нн$', 'н') # end # end _.ends(module, func)
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_noun_specific_1_2(func, i): # export p = i.parts # local if _.contains(i.rest_index, ['%(1%)', '①']): if i.stem.base_type == '1-hard': if i.gender == 'm': p.endings['nom-pl'] = 'а' # end if i.gender == 'n': p.endings['nom-pl'] = 'ы' # end # end if i.stem.base_type == '2-soft': if i.gender == 'm': p.endings['nom-pl'] = 'я' # end if i.gender == 'n': p.endings['nom-pl'] = 'и' # end # end if _.equals(i.stem.type, ['3-velar', '4-sibilant']): # Replace "ы" to "и" if i.gender == 'n': p.endings['nom-pl'] = 'и' # end # end # end if _.contains(i.rest_index, ['%(2%)', '②']): if i.stem.base_type == '1-hard': if i.gender == 'm': p.endings['gen-pl'] = ['', ''] # end if i.gender == 'n': p.endings['gen-pl'] = ['ов', 'ов'] # end if i.gender == 'f': p.endings['gen-pl'] = {'ей', 'ей'} # end # end if i.stem.base_type == '2-soft': if i.gender == 'm': p.endings['gen-pl'] = ['ь', 'ь'] # end if i.gender == 'n': p.endings['gen-pl'] = ['ев', 'ёв'] # end if i.gender == 'f': p.endings['gen-pl'] = {'ей', 'ей'} # end # end if _.equals( i.stem.type, ['4-sibilant', '5-letter-ц']): # Replace unstressed "о" to "е" if i.gender == 'n': p.endings['gen-pl'][unstressed] = 'ев' # end # end # # Possibly we don't need this: # # Replace "ов", "ев", "ёв" and null to "ей" # if i.stem.type = {'4-sibilant'}} # if i.gender == 'n': p.endings['gen-pl'] = ['ей', 'ей'] # if i.gender == 'm': p.endings['gen-pl'][stressed] = 'ей' # # end # # Replace "ь" to "й" # if i.stem.type = ['6-vowel', '7-letter-и']} # if i.gender == 'm': p.endings['gen-pl'][stressed] = ['й', 'й'] # # end # # Replace "ей" to "ев/ёв", and "ь,ей" to "й" # if i.stem.type = ['6-vowel', '7-letter-и']} # if i.gender == 'f': p.endings['gen-pl'][unstressed] = ['ев', 'ёв'] # if i.gender == 'm': p.endings['gen-pl'][stressed] = ['й', 'й'] # # end # # # end _.ends(module, func)
def prt_case(func, i): # Разделительный падеж r = i.result # local if _.contains(i.index, 'Р2') or _.contains(i.index, 'Р₂'): r['prt-sg'] = r['dat-sg'] # end if _.has_value(i.args, 'Р'): r['prt-sg'] = i.args['Р'] # end _.ends(module, func)
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 fix_stress(func, i): # export r = i.result # local # Add stress if there is no one if i.calc_sg and _.contains_several( r['nom-sg'], '{vowel}') and not _.contains(r['nom-sg'], '[́ ё]'): # perhaps this is redundant for nom-sg? _.replace(r, 'nom-sg', '({vowel})({consonant}*)$', '%1́ %2') # end if i.calc_pl and _.contains_several( r['gen-pl'], '{vowel+ё}') and not _.contains(r['gen-pl'], '[́ ё]'): _.replace(r, 'gen-pl', '({vowel})({consonant}*)$', '%1́ %2') # end _.ends(module, func)
def run_gender(func, i): r = i.result # local if _.contains(i.rest_index, '0'): # todo: move to special function # local keys keys = [ # todo: depend on `calc_sg` and `calc_pl` '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] = i.word.stressed # end return _.ends(module, func) # end p.generate_parts(i) res.generate_result(i) _.ends(module, func)
def additional_arguments(func, i): r = i.result # local # RU (склонение) if _.contains(i.rest_index, '0'): r['скл'] = 'не' elif i.adj: r['скл'] = 'а' elif i.pronoun: r['скл'] = 'мс' elif _.endswith(i.word.unstressed, '[ая]'): r['скл'] = '1' else: if i.gender == 'm' or i.gender == 'n': r['скл'] = '2' else: r['скл'] = '3' # end # end # RU (чередование) if _.contains(i.index, '%*'): r['чередование'] = '1' # end if i.pt: r['pt'] = '1' # end # RU ("-" в индексе) # TODO: Здесь может быть глюк, если случай глобального `//` и `rest_index` пуст (а исходный `index` не подходит, т.к. там может быть не тот дефис -- в роде) if i.rest_index: if _.contains(i.rest_index, ['%-', '—', '−']): r['st'] = '1' r['затрудн'] = '1' # end else: pass # TODO # 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 voc_case(func, i): # Звательный падеж r = i.result # local if _.has_value(i.args, 'З'): r['voc-sg'] = i.args['З'] elif _.contains(i.index, 'З'): if _.endswith(i.word.unstressed, ['а', 'я']): r['voc-sg'] = r['gen-pl'] else: r['error'] = 'Ошибка: Для автоматического звательного падежа, слово должно оканчиваться на -а/-я' # end # end _.ends(module, func)
def forward_args(func, i): # export # INFO: Используется дважды -- при инициализации, и потом в самом конце # local keys, args r = i.result # local args = i.args keys = [ 'nom-sg', 'gen-sg', 'dat-sg', 'acc-sg', 'ins-sg', 'prp-sg', 'nom-sg2', 'gen-sg2', 'dat-sg2', 'acc-sg2', 'ins-sg2', 'prp-sg2', 'nom-pl', 'gen-pl', 'dat-pl', 'acc-pl', 'ins-pl', 'prp-pl', 'nom-pl2', 'gen-pl2', 'dat-pl2', 'acc-pl2', 'ins-pl2', 'prp-pl2', 'voc-sg', 'loc-sg', 'prt-sg', 'srt-sg-m', 'srt-sg-f', 'srt-sg-n', 'srt-pl', 'comparative', 'comparative2' ] # list for j, key in enumerate(keys): if _.has_value(args, key): if args[key] == '-': r[key] = args[key] else: r[key] = args[key] + '<sup>△</sup>' # end # end # end keys = [ 'П', 'Пр', 'Сч', 'hide-text', 'зачин', 'слоги', 'дореф', 'скл', 'зализняк', 'зализняк1', 'чередование', 'pt', 'st', 'затрудн', 'клитика', 'коммент', 'тип', 'степень', ] # list for j, key in enumerate(keys): if _.has_value(args, key): r[key] = args[key] # end # end if _.has_key(r, 'слоги'): if not _.contains(r['слоги'], '%<'): r['слоги'] = syllables.get_syllables(r['слоги']) # end else: r['слоги'] = i.word.unstressed # fixme: может всё-таки stressed? # 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 get_stress_schema(func, i): # export if _.contains(i.rest_index, '0'): _.log_info('Игнорируем схему ударения для случая "0"') i.stress_schema = dict() # dict return _.ends(module, func) # end unit = '' # todo: get from i.unit ? if i.adj: unit = 'adj' elif i.pronoun: unit = 'pronoun' else: unit = 'noun' # end _.log_value(unit, 'unit') _.log_value(i.unit, 'i.unit') stress_schemas = json_load( '../modules/dev/dev_py/ru/declension/data/stress/' + unit + '.json') stress_schema = stress_schemas[i.stress_type] # local # ручное клонирование схемы ударения, т.к. потом через mw.clone не работает # ошибка: "table from mw.loadData is read-only" i.stress_schema = dict() # dict types = ['stem', 'ending'] # local for j, type in enumerate(types): i.stress_schema[type] = dict() # dict for case, value in stress_schema[type].items(): i.stress_schema[type][case] = value # end # end _.log_table(i.stress_schema['stem'], "i.stress_schema['stem']") _.log_table(i.stress_schema['ending'], "i.stress_schema['ending']") _.ends(module, func)
def apply_specific_reducable(func, i, gender, rest_index, only_sg): # export # local reduced, reduced_letter, f8_third, prev # local case_2_a, case_2_b, case_2_c, case_3_a, case_3_b # local skip_b_1, skip_b_2, skip_b_3, force_b # local case p = i.parts # local if _.contains(rest_index, '%*'): reduced = '?' if i.adj: if gender == 'm': if _.contains(rest_index, ['%(1%)', '①']): if gender == 'm' and i.adj and _.endswith( i.word.unstressed, 'ний' ) and p.endings[ 'srt-sg'] == 'ь': # fixme: temporary duplicated with the same code at the ending of function... p.endings['srt-sg'] = '' # вместо `ь` для `2*a` # end return _.ends(module, func) # end if _.contains(rest_index, ['%(2%)', '②']): return _.ends(module, func) # end reduced = 'B' else: return _.ends(module, func) # end elif gender == 'm' or i.pronoun: reduced = 'A' elif gender == 'n': reduced = 'B' elif gender == 'f': if i.stem.type == '8-third': reduced = 'A' else: reduced = 'B' # end # end _.log_info('Случай чередования: ' + str(reduced)) if reduced == 'A': reduced_letter = _.extract(i.word.unstressed, '({vowel+ё}){consonant}+$') f8_third = gender == 'f' and i.stem.type == '8-third' _.log_value(reduced_letter, 'reduced_letter') if reduced_letter == 'о': _.replace(p.stems, 'all-sg', '(.)о́ ?([^о]+)$', '%1%2') # # local stem_gen_pl # # У этих имён последняя гласная основы исходной формы заменяется на нуль, о или й во всех формах, не совпадающих с исходной (кроме Т. ед. на -ью). # # if p.endings['gen-pl'] == '': -- ботинок, глазок # if _.contains(rest_index, ['%(2%)', '②']): # stem_gen_pl = p.stems['gen-pl'] # # end if not only_sg: _.replace(p.stems, 'all-pl', '(.)о́ ?([^о]+)$', '%1%2') # end # if stem_gen_pl: # ботинок, глазок # p.stems['gen-pl'] = stem_gen_pl # # end if not f8_third: _.replace(p.stems, 'ins-sg', '(.)о́ ?([^о]+)$', '%1%2') # end elif reduced_letter == 'и': # бывает только в подтипе мс 6* _.replace(p.stems, 'all-sg', '(.)и́ ?([^и]+)$', '%1ь%2') if not only_sg: _.replace(p.stems, 'all-pl', '(.)и́ ?([^и]+)$', '%1ь%2') # end elif _.In(reduced_letter, ['е', 'ё']): prev = _.extract(i.word.unstressed, '(.)[её][^её]+$') case_2_a = i.stem.type == '6-vowel' # 2) а). case_2_b = i.stem.type == '3-velar' and _.contains( prev, '[^аеёиоуыэюяшжчщц]') # 2) б). case_2_c = not _.equals( i.stem.type, ['6-vowel', '3-velar']) and prev == 'л' # 2) в). if _.contains(prev, '{vowel+ё}'): # 1). _.log_info('Подслучай A.1).') _.replace(p.stems, 'all-sg', '[её]́ ?([^её]+)$', 'й%1') if not f8_third: _.replace(p.stems, 'ins-sg', '[её]́ ?([^её]+)$', 'й%1') # end if not only_sg: _.replace(p.stems, 'all-pl', '[её]́ ?([^её]+)$', 'й%1') # end elif case_2_a or case_2_b or case_2_c: # 2). _.log_info('Подслучай A.2).') _.replace(p.stems, 'all-sg', '[её]́ ?([^её]*)$', 'ь%1') if not f8_third: _.replace(p.stems, 'ins-sg', '[её]́ ?([^её]*)$', 'ь%1') # end if not only_sg: _.replace(p.stems, 'all-pl', '[её]́ ?([^её]*)$', 'ь%1') # end else: # 3). _.log_info('Подслучай A.3).') _.replace(p.stems, 'all-sg', '[её]́ ?([^её]*)$', '%1') if not f8_third: _.replace(p.stems, 'ins-sg', '[её]́ ?([^её]*)$', '%1') # end if not only_sg: _.replace(p.stems, 'all-pl', '[её]́ ?([^её]*)$', '%1') # end # end # end # end # reduced A if only_sg: return _.ends( module, func ) # ниже всё равно обрабатывается только множественное число уже # end # we should ignore asterix for 2*b and 2*f (so to process it just like 2b or 2f) skip_b_1 = i.stem.type == '2-soft' and _.In(i.stress_type, ['b', 'f']) # and also the same for (2)-specific and 3,5,6 stem-types skip_b_2 = _.contains(rest_index, ['%(2%)', '②']) and ( _.In(i.stem.type, {'2-soft'}) # '2-soft' из сходня 2*a(2) # TODO: Разобраться, почему это нужно было на самом деле? # _.In(i.stem.type, ['3-velar', '5-letter-ц', '6-vowel']) # так было раньше, без прочих skip ) # TODO: Разобраться, почему это нужно на самом деле? skip_b_3 = _.contains(rest_index, ['%(2%)', '②']) and gender == 'n' # temp fix stem = i.stem.unstressed # local force_b = False if _.contains(rest_index, ['%(2%)', '②']): gender = 'n' # fixme: ???? i.forced_stem = p.stems['gen-pl'] stem = p.stems['gen-pl'] _.log_info('New force stem (gen-pl): ' + str(stem)) force_b = True # end # TODO: б) в словах прочих схем ударения — на последний слог основы, если основа не содержит беглой гласной, и на предпоследний слог основы, если основа содержит беглую гласную, на¬пример: величина, тюрьма, полотно (схема d) — И.мн. величины, тюрьмы, полотна, Р.мн. ве¬личин, тюрем, полотен. # это для глАзок if (reduced == 'B' or force_b) and not skip_b_1 and not skip_b_2 and not skip_b_3: if i.adj: case = 'srt-sg' else: case = 'gen-pl' # end _.log_info('Зашли в случай чередования B') if i.stem.type == '6-vowel': # 1). _.log_info('Подслучай B.1).') if _.In(i.stress_type, { 'b', 'c', 'e', 'f', "f'", "b'" }): # gen-pl ending stressed -- TODO: special vars for that _.replace(p.stems, case, 'ь$', 'е́') else: _.replace(p.stems, case, 'ь$', 'и') # end elif _.contains(stem, '[ьй]{consonant}$'): # 2). _.log_info('Подслучай B.2).') if i.adj: e = i.stem.type == '5-letter-ц' or not _.contains( i.stress_type, 'b') or _.endswith( i.stress_type, ['/b', "/b'"]) # todo: fix only "b" for srt... else: e = i.stem.type == '5-letter-ц' or _.equals( i.stress_type, ['a', 'd', "d'"] ) # gen_pl ending unstressed -- TODO: special vars for that # end if e: _.replace(p.stems, case, '[ьй]({consonant})$', 'е%1') else: _.replace(p.stems, case, '[ьй]({consonant})$', 'ё%1') # end else: # 3). prev = _.extract(stem, '(.){consonant}$') case_3_a = i.stem.type == '3-velar' and _.contains( prev, '[^жшчщц]') # 3). а). case_3_b = _.contains(prev, '[кгх]') # 3). б). if case_3_a or case_3_b: _.log_info('Подслучай B.3). а,б).') _.replace(p.stems, case, '(.)({consonant})$', '%1о%2') else: # 3). в). _.log_info('Подслучай B.3). в).') if i.stem.type == '5-letter-ц': _.log_info('i.stem.type == "letter-ц"') _.replace(p.stems, case, '(.)({consonant})$', '%1е%2') else: if i.adj: e = _.equals(i.stress_type, 'b') or _.endswith( i.stress_type, ['/b', "/b'"]) # TODO: special vars for that else: e = _.In( i.stress_type, {'b', 'c', 'e', 'f', "f'", "b'"} ) # gen_pl ending stressed -- TODO: special vars for that # end if e: _.log_info('в `' + case + '` ударение на окончание') p.stems[case] = stem if _.contains(prev, '[жшчщ]'): _.log_info('предыдущая [жшчщ]') _.replace(p.stems, case, '(.)({consonant})$', '%1о́%2') else: _.log_info('предыдущая не [жшчщ]') _.replace(p.stems, case, '(.)({consonant})$', '%1ё%2') # end else: _.log_info('ударение на основу в ["' + case + '"] ') _.replace(p.stems, case, '(.)({consonant})$', '%1е%2') # end # end # end # end if i.stem.type == '2-soft' and _.endswith( i.word.unstressed, 'ня' ) and i.stress_type == 'a' and p.endings['gen-pl'] == 'ь': p.endings['gen-pl'] = '' # вместо `ь` для `2*a` # end if gender == 'm' and i.adj and _.endswith( i.word.unstressed, 'ний') and p.endings['srt-sg'] == 'ь': p.endings['srt-sg'] = '' # вместо `ь` для `2*a`
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 parse(func, base, args, frame): # export i = a.AttrDict() # AttrDict # local i.word = a.AttrDict() # AttrDict i.stem = a.AttrDict() # AttrDict i.parts = a.AttrDict() # AttrDict i.result = a.AttrDict() # AttrDict i.result.error = '' i.has_index = True # изначально предполагаем, что индекс есть # INFO: Достаём значения из параметров: i.base = base i.args = args i.frame = frame i.lang = mw.text.trim(args['lang']) i.unit = mw.text.trim(args['unit']) i.index = mw.text.trim(args['индекс']) i.word.stressed = mw.text.trim(args['слово']) i.noun = (i.unit == 'noun') _.log_value(i.index, 'i.index') _.log_value(i.word.stressed, 'i.word.stressed') # mw.log('') # mw.log('==================================================') # mw.log('args: ' + str(i.index) + ' | ' + str(i.word.stressed)) # mw.log('--------------------------------------------------') _.log_info('Получение информации о роде и одушевлённости') if i.noun: # fixme noun_parse.extract_gender_animacy(i) if e.has_error(i): return _.returns(module, func, i) # end # Будем расчитывать оба числа сразу вместе i.calc_sg = True i.calc_pl = True _.log_value(i.gender, 'i.gender') _.log_value(i.animacy, 'i.animacy') _.log_value(i.common_gender, 'i.common_gender') _.log_value(i.adj, 'i.adj') _.log_value(i.pronoun, 'i.pronoun') else: i.gender = '' # fixme i.animacy = '' # fixme i.adj = True # fixme i.rest_index = i.index # fixme # Будем расчитывать позже по отдельности i.calc_sg = False i.calc_pl = False # end _.log_value(i.pt, 'i.pt') _.log_value(i.rest_index, 'i.rest_index') # INFO: stem, stem.stressed, etc. init_stem.init_stem(i) if e.has_error(i): return _.returns(module, func, i) # end if i.noun: # INFO: Случай, если род или одушевлённость не указаны: if (not i.gender or not i.animacy) and not i.pt: # INFO: Не показываем ошибку, просто считаем, что род или одушевлённость *ещё* не указаны return _.returns(module, func, i) # end # end # INFO: Проверяем случай с вариациями: variations = mw.text.split(i.rest_index, '//') # local n_variations = a.table_len(variations) # local if n_variations == 1: # INFO: Дополнительных вариаций нет if _.contains(i.animacy, '//'): # INFO: Случаи 'in//an' и 'an//in' v.process_animacy_variations(i) return _.returns(module, func, i) # TODO: А что если in//an одновременно со следующими случаями "[]" или "+" # end # _.log_info('Случай с "+" (несколько составных частей слова через дефис)') plus_index = mw.text.split(i.rest_index, '%+') # local plus_words = mw.text.split(i.word.stressed, '-') # local n_plus = a.table_len(plus_index) # local if n_plus > 1: v.process_plus(i, plus_words, plus_index) return _.returns(module, func, i) # end if i.noun: angle.angle_brackets(i) if e.has_error(i): return _.returns(module, func, i) # end # end if _.contains(i.rest_index, '%[%([12]%)%]') or _.contains( i.rest_index, '%[[①②]%]'): v.process_brackets_variations(i) return _.returns(module, func, i) # end elif n_variations == 2: # INFO: Вариации "//" для ударения (и прочего индекса) _.log_info('> Случай с вариациями //') if _.contains(i.animacy, '//'): # INFO: Если используются вариации одновременно и отдельно для одушевлённости и ударения e.add_error( i, 'Ошибка: Случай с несколькими "//" пока не реализован. Нужно реализовать?' ) return _.returns(module, func, i) # end v.process_full_variations(i, variations) return _.returns(module, func, i) else: # INFO: Какая-то ошибка, слишком много "//" в индексе e.add_error(i, 'Ошибка: Слишком много частей для "//"') return _.returns(module, func, i) # end _.ends(module, func) return p.process(i)
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)
def apply_specific_degree(func, i): # export # If degree sign ° p = i.parts # local word = i.word.unstressed # local if _.contains(i.rest_index, '°') and _.endswith(word, '[ая]нин'): _.replace(p.stems, 'all-pl', '([ая])ни́ н$', '%1́ н') _.replace(p.stems, 'all-pl', '([ая]́ ?н)ин$', '%1') p.endings['nom-pl'] = 'е' p.endings['gen-pl'] = '' return _.returns(module, func, i.rest_index) # end if _.contains(i.rest_index, '°') and _.endswith(word, 'ин'): _.replace(p.stems, 'all-pl', 'и́ ?н$', '') if not _.contains(i.rest_index, ['%(1%)', '①']): p.endings['nom-pl'] = 'е' # end p.endings['gen-pl'] = '' # end if _.contains(i.rest_index, '°') and _.endswith(word, ['ёнок', 'онок']): _.replace(p.stems, 'all-pl', 'ёнок$', 'я́т') _.replace(p.stems, 'all-pl', 'о́нок$', 'а́т') # INFO: Эмуляция среднего рода `1a` для форм мн. числа p.endings['nom-pl'] = 'а' p.endings['gen-pl'] = '' reducable.apply_specific_reducable(i, i.gender, i.rest_index + '*', True) return _.returns(module, func, i.rest_index) # end if _.contains(i.rest_index, '°') and _.endswith(word, ['ёночек', 'оночек']): _.replace(p.stems, 'all-pl', 'ёночек$', 'я́тк') _.replace(p.stems, 'all-pl', 'о́ночек$', 'а́тк') # INFO: Черездование для единичной формы (возможно применится также и для множественной, но это не страшно, потом заменится по идее) reducable.apply_specific_reducable(i, i.gender, i.rest_index + '*', False) # INFO: По сути должно примениться только к мн. формам (случай `B`) reducable.apply_specific_reducable(i, 'f', i.rest_index + '*', False) p.endings['gen-pl'] = '' # INFO: Странный фикс, но он нужен.. <_< return _.returns(module, func, i.rest_index) # end if _.contains(i.rest_index, '°') and i.gender == 'n' and _.endswith( word, 'мя'): _.replace(p.stems, 'all-sg', 'м$', 'мен') _.replace(p.stems, 'ins-sg', 'м$', 'мен') _.replace(p.stems, 'all-pl', 'м$', 'мен') p.endings['nom-sg'] = 'я' p.endings['gen-sg'] = 'и' p.endings['dat-sg'] = 'и' p.endings['ins-sg'] = 'ем' p.endings['prp-sg'] = 'и' # end return _.returns(module, func, i.rest_index)
def get_stem_type(func, i): # export # INFO: Определение типа основы word = i.word.unstressed # local stem = i.stem.unstressed # local i.stem.type = '' if _.endswith(stem, '[гкх]'): i.stem.type = '3-velar' elif _.endswith(stem, '[жчшщ]'): i.stem.type = '4-sibilant' elif _.endswith(stem, 'ц'): i.stem.type = '5-letter-ц' elif _.endswith(stem, ['[йь]', '[аоеёуыэюя]']): i.stem.type = '6-vowel' elif _.endswith(stem, 'и'): i.stem.type = '7-letter-и' else: if i.adj: if _.endswith(word, ['ый', 'ой', 'ая', 'ое', 'ые']): i.stem.type = '1-hard' elif _.endswith(word, ['ий', 'яя', 'ее', 'ие']): i.stem.type = '2-soft' # end elif i.gender == 'm': if stem == word or _.endswith(word, 'ы'): i.stem.type = '1-hard' elif _.endswith(word, 'путь'): i.stem.type = '8-third' elif _.endswith(word, 'ь') or _.endswith(word, 'и'): i.stem.type = '2-soft' elif _.endswith(word, 'а'): i.stem.type = '1-hard' # i.gender = 'f' ?? elif _.endswith(word, 'я'): i.stem.type = '2-soft' # i.gender = 'f' ?? # end elif i.gender == 'f': if _.endswith(word, 'а') or _.endswith(word, 'ы'): i.stem.type = '1-hard' elif _.endswith(word, 'я'): i.stem.type = '2-soft' elif _.endswith(word, 'и') and _.contains( i.rest_index, '2'): # todo: а что если нет индекса?? i.stem.type = '2-soft' elif _.endswith(word, 'и') and _.contains(i.rest_index, '8'): i.stem.type = '8-third' elif _.endswith(word, 'ь'): # conflict in pl i.stem.type = '8-third' # end elif i.gender == 'n': if _.endswith(word, 'о') or _.endswith(word, 'а'): i.stem.type = '1-hard' elif _.endswith(word, 'мя') or _.endswith(word, 'мена'): i.stem.type = '8-third' elif _.endswith(word, 'е') or _.endswith(word, 'я'): i.stem.type = '2-soft' # end # end # end # if gender == 'm': # if _.endswith(word, ['а', 'я']): # i.gender = 'f' # # end # # end if i.gender == 'f' and i.stem.type == '4-sibilant' and _.endswith( word, 'ь'): i.stem.type = '8-third' # end if i.stem.type == '': i.stem.type = '1-hard' # e.add_error(i, 'Неизвестный тип основы') -- fixme ? # return _.ends(module, func) # end # INFO: Выбор подходящего `stem_type` из двух базовых типов: '1-hard' и '2-soft' i.stem.base_type = get_stem_base_type(i) _.ends(module, func)
def apply_obelus(func, i): # export if _.contains(i.rest_index, '÷'): i.result['obelus'] = '1' # end _.ends(module, func)