def forms(func, base, args, frame): # export # todo: rename to `out_args` i = init.init_info(base, args, frame) # local if e.has_error(i): return _.returns(module, func, i.result) # end # INFO: Запуск основного алгоритма и получение результирующих словоформ: run.run(i) return _.returns(module, func, i.result)
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 generate_pronoun_noun_endings(func): endings = base_pronoun_noun_endings() # local copy_common_endings(endings) copy_other_endings(endings, genders) fill_other_pronoun_noun_endings(endings) dump_data('pronoun', endings) return _.returns(module, func, endings)
def get_stem_base_type(func, i): # INFO: Выбор подходящего из двух типов if _.equals(i.stem.type, ['1-hard', '3-velar', '4-sibilant', '5-letter-ц']): return _.returns(module, func, '1-hard') # end if _.equals(i.stem.type, ['2-soft', '6-vowel', '7-letter-и']): return _.returns(module, func, '2-soft') # end if _.equals(i.stem.type, {'8-third'}): if i.gender == 'n': return _.returns(module, func, '1-hard') # end if i.gender == 'm' or i.gender == 'f': return _.returns(module, func, '2-soft') # end # end return _.returns(module, func, '?')
def plus_forms(func, sub_forms): # export # todo: rename to `out_args` # local keys, out_args, delim 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', 'ins-sg2', 'зализняк1', 'зализняк', 'error', ] # list out_args = sub_forms[0] # todo: rename to `out_args` for j, forms2 in enumerate(sub_forms): # todo: rename to `out_args` if j != 0: for j, key in enumerate(keys): if not out_args[key] and forms2[ key]: # INFO: Если out_args[key] == None out_args[key] = forms2[key] elif out_args[key] != forms2[key] and forms2[key]: delim = '-' if _.equals(key, ['зализняк1', 'зализняк']): delim = ' + ' # end out_args[key] = out_args[key] + delim + forms2[key] # end if not out_args[key]: # INFO: Если out_args[key] == None out_args[key] = '' # end # end # end # end return _.returns(module, func, out_args)
def generate_pronoun_stress_schemas(func): # INFO: Вычисление схемы ударения stress_types = ['a', 'b'] # local res = dict() # dict for j, stress_type in enumerate(stress_types): stress_schema = dict() # dict stress_schema['stem'] = dict() # dict stress_schema['ending'] = dict() # dict # общий подход следующий: # если схема среди перечисленных, значит, элемент под ударением (stressed), иначе — нет (unstressed) stress_schema['stem']['sg'] = _.equals(stress_type, "a") stress_schema['stem']['pl'] = _.equals(stress_type, "a") stress_schema['ending']['sg'] = _.equals(stress_type, "b") stress_schema['ending']['pl'] = _.equals(stress_type, "b") types = ['stem', 'ending'] sg_cases = ['nom-sg', 'gen-sg', 'dat-sg', 'acc-sg', 'ins-sg', 'prp-sg'] # list pl_cases = ['nom-pl', 'gen-pl', 'dat-pl', 'acc-pl', 'ins-pl', 'prp-pl'] # list for j, type in enumerate(types): sg_value = stress_schema[type]['sg'] for j, case in enumerate(sg_cases): stress_schema[type][case] = sg_value # end del stress_schema[type]['sg'] pl_value = stress_schema[type]['pl'] for j, case in enumerate(pl_cases): stress_schema[type][case] = pl_value # end del stress_schema[type]['pl'] # end res[stress_type] = stress_schema # end dump_data('pronoun', res) return _.returns(module, func, res)
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 init_info(func, base, args, frame): # export prepare_regexp_patterns() # INFO: Заполняем шаблоны для регулярок i = parse.parse(base, args, frame) return _.returns(module, func, i)
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 generate_adj_stress_schemas(func): # INFO: Вычисление схемы ударения stress_types = [ # todo: special variables for that? 'a', "a'", 'b', "b'", 'c', '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''", ] res = dict() # dict for j, stress_type in enumerate(stress_types): stress_schema = dict() # dict stress_schema['stem'] = dict() # dict stress_schema['ending'] = dict() # dict # local cases cases = [ '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 # пустышки в падежи, чтобы они шли раньше кратких форм в результате types = ['stem', 'ending'] # local for j, type in enumerate(types): for j, case in enumerate(cases): stress_schema[type][case] = '...' # end # end # общий подход следующий: # если схема среди перечисленных, значит, элемент под ударением (stressed), иначе — нет (unstressed) stress_schema['stem']['full'] = _.startswith(stress_type, ["a", "a/"]) stress_schema['stem']['srt-sg-m'] = True stress_schema['stem']['srt-sg-f'] = _.endswith( stress_type, ["/a", "/a'"]) or _.equals(stress_type, ['a', "a'"]) stress_schema['stem']['srt-sg-n'] = _.endswith( stress_type, ["/a", "/c", "/a'", "/c'", "/c''"]) or _.equals( stress_type, ['a', "a'"]) stress_schema['stem']['srt-pl'] = _.endswith( stress_type, ["/a", "/c", "/a'", "/b'", "/c'", "/c''" ]) or _.equals(stress_type, ['a', "a'", "b'"]) stress_schema['ending']['full'] = _.startswith(stress_type, ["b", "b/"]) stress_schema['ending']['srt-sg-m'] = False stress_schema['ending']['srt-sg-f'] = _.endswith( stress_type, ["/b", "/c", "/a'", "/b'", "/c'", "/c''" ]) or _.equals(stress_type, ['b', "a'", "b'"]) stress_schema['ending']['srt-sg-n'] = _.endswith( stress_type, ["/b", "/b'", "/c''"]) or _.equals( stress_type, ['b', "b'"]) stress_schema['ending']['srt-pl'] = _.endswith( stress_type, ["/b", "/b'", "/c'", "/c''"]) or _.equals( stress_type, ['b', "b'"]) types = ['stem', 'ending'] # local for j, type in enumerate(types): value = stress_schema[type]['full'] # local for j, case in enumerate(cases): stress_schema[type][case] = value # end del stress_schema[type]['full'] # end res[stress_type] = stress_schema # end dump_data('adj', res) return _.returns(module, func, res)
def generate_noun_stress_schemas(func): # INFO: Вычисление схемы ударения # todo: special variable for this? stress_types = ['a', 'b', 'c', 'd', 'e', 'f', "b'", "d'", "f'", "f''"] # local res = dict() # dict for j, stress_type in enumerate(stress_types): stress_schema = dict() # dict stress_schema['stem'] = dict() # dict stress_schema['ending'] = dict() # dict # общий подход следующий: # если схема среди перечисленных, значит, элемент под ударением (stressed), иначе — нет (unstressed) stress_schema['stem']['sg'] = _.equals(stress_type, ["a", "c", "e"]) stress_schema['stem']['nom-sg'] = '...' stress_schema['stem']['gen-sg'] = '...' stress_schema['stem']['dat-sg'] = '...' stress_schema['stem']['acc-sg'] = _.equals(stress_type, ["a", "c", "e", "d'", "f'"]) stress_schema['stem']['ins-sg'] = _.equals( stress_type, ["a", "c", "e", "b'", "f''"]) stress_schema['stem']['prp-sg'] = '...' stress_schema['stem']['pl'] = _.equals(stress_type, ["a", "d", "d'"]) stress_schema['stem']['nom-pl'] = _.equals( stress_type, ["a", "d", "d'", "e", "f", "f'", "f''"]) stress_schema['stem']['gen-pl'] = '...' stress_schema['stem']['dat-pl'] = '...' stress_schema['stem']['ins-pl'] = '...' stress_schema['stem']['prp-pl'] = '...' stress_schema['ending']['sg'] = _.equals( stress_type, ["b", "b'", "d", "d'", "f", "f'", "f''"]) stress_schema['ending']['nom-sg'] = '...' stress_schema['ending']['gen-sg'] = '...' stress_schema['ending']['dat-sg'] = '...' stress_schema['ending']['acc-sg'] = _.equals( stress_type, ["b", "b'", "d", "f", "f''"]) stress_schema['ending']['ins-sg'] = _.equals( stress_type, ["b", "d", "d'", "f", "f'"]) stress_schema['ending']['prp-sg'] = '...' stress_schema['ending']['pl'] = _.equals( stress_type, ["b", "b'", "c", "e", "f", "f'", "f''"]) stress_schema['ending']['nom-pl'] = _.equals(stress_type, ["b", "b'", "c"]) stress_schema['ending']['gen-pl'] = '...' stress_schema['ending']['dat-pl'] = '...' stress_schema['ending']['ins-pl'] = '...' stress_schema['ending']['prp-pl'] = '...' types = ['stem', 'ending'] # local for j, type in enumerate(types): sg_value = stress_schema[type]['sg'] # local stress_schema[type]['nom-sg'] = sg_value stress_schema[type]['gen-sg'] = sg_value stress_schema[type]['dat-sg'] = sg_value stress_schema[type]['prp-sg'] = sg_value del stress_schema[type]['sg'] pl_value = stress_schema[type]['pl'] # local stress_schema[type]['gen-pl'] = pl_value stress_schema[type]['dat-pl'] = pl_value stress_schema[type]['ins-pl'] = pl_value stress_schema[type]['prp-pl'] = pl_value del stress_schema[type]['pl'] # end res[stress_type] = stress_schema # end dump_data('noun', res) return _.returns(module, func, res)
def join_forms(func, out_args_1, out_args_2): # export # todo: rename to `variations` # local keys, out_args, delim 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', 'nom-sg-m', 'gen-sg-m', 'dat-sg-m', 'acc-sg-m', 'ins-sg-m', 'prp-sg-m', 'nom-sg-n', 'gen-sg-n', 'dat-sg-n', 'acc-sg-n', 'ins-sg-n', 'prp-sg-n', 'nom-sg-f', 'gen-sg-f', 'dat-sg-f', 'acc-sg-f', 'ins-sg-f', 'prp-sg-f', 'srt-sg', 'srt-sg-m', 'srt-sg-n', 'srt-sg-f', 'srt-pl', 'acc-sg-m-a', 'acc-sg-m-n', 'acc-pl-a', 'acc-pl-n', 'ins-sg2', 'ins-sg2-f', 'зализняк1', 'зализняк', 'error', ] # list out_args = out_args_1 out_args['зализняк-1'] = out_args_1['зализняк'] out_args['зализняк-2'] = out_args_2['зализняк'] for j, key in enumerate(keys): if not _.has_key(out_args, key) and not _.has_key(out_args_2, key): pass elif not _.has_key(out_args, key) and _.has_key( out_args_2, key): # INFO: Если out_args[key] == None out_args[key] = out_args_2[key] elif out_args[key] != out_args_2[key] and out_args_2[key]: delim = '<br/>' if _.equals(key, ['зализняк1', 'зализняк']): delim = ' ' # end # TODO: <br/> только для падежей out_args[ key] = out_args[key] + ' //' + delim + out_args_2[key] # end if not _.has_key( out_args, key) or not out_args[key]: # INFO: Если out_args[key] == None out_args[key] = '' # end # end return _.returns(module, func, out_args)