Исходный код rupo.main.phonetics

# -*- coding: utf-8 -*-
# Автор: Гусев Илья
# Описание: Модуль разбивки на слоги, проставления ударений и получения начальной разметки.

from typing import List

from rupo.accents.dict import AccentDict
from rupo.main.markup import Syllable, Word, Markup, Line
from rupo.util.preprocess import count_vowels, get_first_vowel_position, \
    VOWELS, CLOSED_SYLLABLE_CHARS


[документация]class Phonetics: """ Класс-механизм для фонетического анализа слов. """ @staticmethod
[документация] def get_word_syllables(word: str) -> List[Syllable]: """ Разделение слова на слоги. :param word: слово для разбивки на слоги. :return syllables: массив слогов слова. """ syllables = [] begin = 0 number = 0 for i in range(len(word)): if word[i] not in VOWELS: continue if i+1 < len(word)-1 and word[i+1] in CLOSED_SYLLABLE_CHARS: if i+2 < len(word)-1 and word[i+2] in "ьЬ": # Если после сонорного согласного идёт мягкий знак, заканчиваем на нём. ("бань-ка") end = i+3 elif i+2 < len(word)-1 and word[i+2] not in VOWELS and \ (word[i+2] not in CLOSED_SYLLABLE_CHARS or word[i+1] == "й"): # Если после сонорного согласного не идёт гласная или другой сонорный согласный, # слог закрывается на этом согласном. ("май-ка") end = i+2 else: # Несмотря на наличие закрывающего согласного, заканчиваем на гласной. # ("со-ло", "да-нный", "пол-ный") end = i+1 else: # Если после гласной идёт не закрывающая согласная, заканчиваем на гласной. ("ко-гда") end = i+1 syllables.append(Syllable(begin, end, number, word[begin:end])) number += 1 begin = end if get_first_vowel_position(word) != -1: # Добиваем последний слог до конца слова. syllables[-1] = Syllable(syllables[-1].begin, len(word), syllables[-1].number, word[syllables[-1].begin:len(word)]) return syllables
@staticmethod
[документация] def get_word_accents(word: str, accents_dict: AccentDict) -> List[int]: """ Определение ударения в слове по словарю. Возможно несколько вариантов ударения. :param word: слово для простановки ударений. :param accents_dict: экземпляр обёртки для словаря ударений. :return accents: позиции букв, на которые падает ударение. """ accents = [] if count_vowels(word) == 0: # Если гласных нет, то и ударений нет. pass elif count_vowels(word) == 1: # Если одна гласная, то на неё и падает ударение. accents.append(get_first_vowel_position(word)) elif word.find("ё") != -1: # Если есть буква "ё", то только на неё может падать ударение. accents.append(word.find("ё")) else: # Проверяем словарь на наличие форм с ударениями. accents = accents_dict.get_accents(word) if 'е' not in word: return accents # Находим все возможные варинаты преобразований 'е' в 'ё'. positions = [i for i in range(len(word)) if word[i] == 'е'] beam = [word[:positions[0]]] for i in range(len(positions)): new_beam = [] for prefix in beam: n = positions[i+1] if i+1 < len(positions) else len(word) new_beam.append(prefix + 'ё' + word[positions[i]+1:n]) new_beam.append(prefix + 'е' + word[positions[i]+1:n]) beam = new_beam # И проверяем их по словарю. for permutation in beam: if len(accents_dict.get_accents(permutation)) != 0: yo_pos = permutation.find("ё") if yo_pos != -1: accents.append(yo_pos) return accents
@staticmethod
[документация] def process_text(text: str, accents_dict: AccentDict) -> Markup: """ Получение начального варианта разметки по слогам и ударениям. :param text: текст для разметки :param accents_dict: экземпляр обёртки для словаря ударений :return markup: разметка по слогам и ударениям """ begin_word = -1 begin_line = 0 lines = [] words = [] # TODO: Нормальная токенизация. for i in range(len(text)): valid_word_symbol = text[i].isalpha() and i != len(text) - 1 if valid_word_symbol and begin_word == -1: begin_word = i if not valid_word_symbol and begin_word != -1: # Каждое слово разбиваем на слоги. word = Word(begin_word, i, text[begin_word:i], Phonetics.get_word_syllables(text[begin_word:i])) # Проставляем ударения. accents = Phonetics.get_word_accents(word.text.lower(), accents_dict) # Сопоставляем ударения слогам. word.set_accents(accents) words.append(word) begin_word = -1 if text[i] == "\n": # Разбиваем по строкам. lines.append(Line(begin_line, i+1, text[begin_line:i], words)) words = [] begin_line = i+1 if begin_line != len(text): lines.append(Line(begin_line, len(text), text[begin_line:len(text)], words)) return Markup(text, lines)
@staticmethod
[документация] def get_improved_word_accent(word: str, accent_dict: AccentDict, accent_classifier) -> int: """ Получение ударения с учётом классификатора. :param word: слово. :param accent_dict: словарь ударений. :param accent_classifier: классификатор ударений. :return: индекс ударения. """ dict_accents = Phonetics.get_word_accents(word, accent_dict) if len(dict_accents) == 1: return dict_accents[0] elif len(dict_accents) == 0: clf_accent = accent_classifier.classify_accent(word) return clf_accent else: clf_accent = accent_classifier.classify_accent(word) intersection = list(set(dict_accents).intersection({clf_accent})) if len(intersection) != 0: return intersection[0] else: return dict_accents[0]