mod: изменен алгоритм переноса в русских словах

This commit is contained in:
2025-07-24 13:16:18 +03:00
parent aa3939d1c6
commit 086adc1f7b
2 changed files with 56 additions and 19 deletions

View File

@@ -128,7 +128,7 @@ class Hyphenator:
# 1. ОБЩИЕ ПРОВЕРКИ
# TODO: возможно, для скорости, надо сделать проверку на пробелы и другие разделители, которых не должно быть
if not word:
# Добавим явную проверку на пустую строку
# Явная проверка на пустую строку
return ""
if len(word) <= self.max_unhyphenated_len or not any(self._is_vow(c) for c in word):
# Если слово короткое или не содержит гласных, перенос не нужен
@@ -140,29 +140,61 @@ class Hyphenator:
if (LANG_RU in self.langs or LANG_RU_OLD in self.langs) and frozenset(word.upper()) <= self._ru_alphabet_upper:
# Пользователь подключил русскую логику, и слово содержит только русские буквы
logger.debug(f"`{word}` -- use `{LANG_RU}` or `{LANG_RU_OLD}` rules")
# Поиск допустимой позиции для переноса около заданного индекса
def find_hyphen_point_ru(word_segment: str, start_idx: int) -> int:
vow_indices = [i for i, char_w in enumerate(word_segment) if self._is_vow(char_w)]
# Если в слове нет гласных, то перенос невозможен
if not vow_indices:
return -1
word_segment_len = len(word_segment)
# Ищем ближайшую гласную до или после start_idx
for i in vow_indices:
if i >= start_idx - self.min_chars_per_part and i + self.min_chars_per_part < len(word_segment):
if i >= start_idx - self.min_chars_per_part and i + self.min_chars_per_part < word_segment_len:
# Проверяем, что после гласной есть минимум символов "хвоста"
ind = i + 1
# 1. Не отделяем "хвостов" с начала или конца (это некрасиво)
if ind <= self.min_chars_per_part or ind >= len(word_segment) - self.min_chars_per_part:
if ind <= self.min_chars_per_part or ind >= word_segment_len - self.min_chars_per_part:
continue
# 2. Пропускаем мягкий/твердый знак, если перенос начинается или заканчивается
# на них (правило из ГОСТ 7.62-2008)
if self._is_sign(word_segment[ind]) or (ind > 0 and self._is_sign(word_segment[ind-1])):
# 2. Сдвигаем перенос за мягкий/твердый знак, если он сразу за согласной (ГОСТ 7.62-2008)
if self._is_sign(word_segment[ind]):
# 2.1 Текущая буква мягкий/твердый знак. Ставим перенос за ней (индекс ind+1).
return ind + 1
if (self._is_cons(word_segment[ind]) and
i+1 < word_segment_len and self._is_sign(word_segment[ind+1])):
# 2.2 Текущая буква согласная, а следующая мягкий/твердый знак. Ставим перенос за ней
return ind+2
# 3. Проверка на `Й` (полугласная). Не бывает слов, когда сразу не ней идет гласная,
# или перед ней идет согласная. Сдвигает перенос за полугласную букву если она идет после
# гласной.
if self._is_j_sound(word_segment[ind+1]):
# 3.1 Текущая буква `й`. Ставим за ней перенос (индекс ind+1).
return ind+1
if (self._is_vow(word_segment[ind]) and
i+1 < word_segment_len and self._is_j_sound(word_segment[ind+1])):
# 3.2 Текущая буква гласная, а следующая `й`. Ставим перенос за `й` (индекс ind+2).
# Ставим перенос за `й` (индекс ind+2).
return ind+2
# 4. Проверка на сдвоенная-согласная (C-C).
if (self._is_cons(word_segment[ind]) and
i+1 < word_segment_len and word_segment[ind] == word_segment[ind+1]):
print("сдвоенная согласная")
# 4.1 Текущая буква согласная и следующая така же (сдвоенная согласная). Ставим перенос
# за ней (индекс ind+1).
return ind + 1
if (self._is_cons(word_segment[ind]) and
i+1 < word_segment_len and self._is_cons(word_segment[ind+1])):
# 4.2 НЕ ОБЯЗАТЕЛЬНОЕ ПРАВИЛО: Текущая буква согласная, а следующая тоже согласная.
# Ставим перенос за ней (индекс ind+1).
return ind+1
# 5. Проверка на гласная-гласная (V-V).
if (self._is_vow(word_segment[ind]) and
i+1 < word_segment_len and self._is_vow(word_segment[ind+1])):
# 5.1 Текущая буква гласная, а следующая гласная. Перенос не делаем. Возможно,
# надо дальше искать до ближайшей согласной, но это усложнит алгоритм.
continue
# 3. Провека на `Й` (полугласная). Перенос после неё только в случае, если дальше идет
# согласная (например, "бой-кий"), но запретить, если идет гласная (например,
# "ма-йка" не переносится).
if (self._is_cons(word_segment[ind]) or self._is_j_sound(word_segment[ind])) and not self._is_vow(word_segment[ind + 1]):
ind += 1
# 6. TODO (опционально): Проверка на суффикс и приставку (не разбивать). Нужен словарь.
# 7. TODO (опционально): Проверка на короткий корень (не разбивать). Нужен очень большой словарь.
return ind
return -1 # Не нашли подходящую позицию

View File

@@ -11,19 +11,24 @@ RUSSIAN_HYPHENATION_CASES = [
("тестирование", "тести\u00ADрование"),
("благотворительностью", "благотво\u00ADритель\u00ADностью"), # Слово с переносом на мягкий знак
("гиперподъездной", "гипер\u00ADподъ\u00ADездной"), # Слово с переносом на твердый знак
("фотоаппаратура", "фотоап\u00ADпара\u00ADтура"), # проверка слова с двойной согласной
("фотоаппаратура", "фотоап\u00ADпара\u00ADтура"), # проверка слова со сдвоенной согласной
("программирование", "програм\u00ADмиро\u00ADвание"), # слова со сдвоенной согласной
("сверхзвуковой", "сверхзву\u00ADковой"),
("автомобиль", "авто\u00ADмобиль"), # Слово с переносом на мягкий знак
("интернационализация", "интерна\u00ADциона\u00ADлизация"), # Длинное слово с переносами
("программирование", "програм\u00ADмиро\u00ADвание"),
("автомобиль", "авто\u00ADмобиль"),
("интернационализация", "интерна\u00ADциона\u00ADлизация"),
("суперкомпьютер", "супер\u00ADком\u00ADпьютер"),
("электронный", "электрон\u00ADный"),
("информационный", "информа\u00ADционный"),
("автоматизация", "авто\u00ADмати\u00ADзация"),
("многоклеточный", "многок\u00ADлеточ\u00ADный"), # Сложное слово с переносами
("многофункциональный", "многофун\u00ADкцио\u00ADнальный"), # Сложное слово с переносами
("непрерывность", "непре\u00ADрывность"), # Слово с мягким знаком в конце
("сверхпроводимость", "сверхпро\u00ADводи\u00ADмость"), # Слово с мягким знаком в середине
("многоклеточный", "многок\u00ADлеточ\u00ADный"),
("многофункциональный", "многофун\u00ADкцио\u00ADнальный"),
("непрерывность", "непре\u00ADрывность"),
("сверхпроводимость", "сверхпро\u00ADводи\u00ADмость"),
("многообразие", "много\u00ADобразие"),
("противоречивость", "противо\u00ADречи\u00ADвость"),
("сверхчувствительный", "сверхчув\u00ADстви\u00ADтельный"), # Будет неправильный перенос, (словарь "корней")
("непревзойденный", "непрев\u00ADзойден\u00ADный"), # Будет неправильный перенос
("многослойный", "многос\u00ADлойный"), # Будет неправильный перенос,
]