mod: minor .

This commit is contained in:
Sergei Erjemin 2025-05-13 00:46:36 +03:00
parent 8b0efa26eb
commit f48dd5bb53
5 changed files with 47 additions and 31 deletions

View File

@ -12,3 +12,4 @@ __version__ = "0.1.0"
from etpgrf.typograph import Typographer from etpgrf.typograph import Typographer
from etpgrf.hyphenation import Hyphenator from etpgrf.hyphenation import Hyphenator
import etpgrf.config

View File

@ -14,7 +14,10 @@ LANG_EN = 'en' # Английский
SUPPORTED_LANGS = frozenset([LANG_RU, LANG_EN]) SUPPORTED_LANGS = frozenset([LANG_RU, LANG_EN])
# Язык(и) по умолчанию, если не указаны пользователем и не заданы через ETPGRF_DEFAULT_LANGS_MODULE # Язык(и) по умолчанию, если не указаны пользователем и не заданы через ETPGRF_DEFAULT_LANGS_MODULE
DEFAULT_LANGS = LANG_RU DEFAULT_LANGS = LANG_RU
#
# Значения по умолчанию для параметров Hyphenator
DEFAULT_HYP_MAX_LEN = 10 # Максимальная длина слова без переносов
DEFAULT_HYP_MIN_LEN = 3 # Минимальный "хвост" слова для переноса
# ----------------- соответствия `unicode` и `mnemonic` для типографа # ----------------- соответствия `unicode` и `mnemonic` для типографа

View File

@ -1,5 +1,5 @@
import regex import regex
from etpgrf.config import LANG_RU, LANG_EN, DEFAULT_MODE, DEFAULT_LANGS, SHY_ENTITIES, MODE_UNICODE from etpgrf.config import LANG_RU, LANG_EN, SHY_ENTITIES, MODE_UNICODE, DEFAULT_HYP_MAX_LEN, DEFAULT_HYP_MIN_LEN
from etpgrf.comutil import parse_and_validate_mode, parse_and_validate_langs from etpgrf.comutil import parse_and_validate_mode, parse_and_validate_langs
_RU_VOWELS_UPPER = frozenset(['А', 'О', 'И', 'Е', 'Ё', 'Э', 'Ы', 'У', 'Ю', 'Я']) _RU_VOWELS_UPPER = frozenset(['А', 'О', 'И', 'Е', 'Ё', 'Э', 'Ы', 'У', 'Ю', 'Я'])
@ -17,8 +17,8 @@ class Hyphenator:
def __init__(self, def __init__(self,
langs: str | list[str] | tuple[str, ...] | frozenset[str] | None = None, langs: str | list[str] | tuple[str, ...] | frozenset[str] | None = None,
mode: str = None, # Режим обработки текста mode: str = None, # Режим обработки текста
max_unhyphenated_len: int = 14, # Максимальная длина непереносимой группы max_unhyphenated_len: int = DEFAULT_HYP_MAX_LEN, # Максимальная длина непереносимой группы
min_chars_per_part: int = 3): # Минимальная длина после переноса (хвост, который разрешено переносить) min_chars_per_part: int = DEFAULT_HYP_MIN_LEN): # Минимальная длина после переноса (хвост, который разрешено переносить)
self.langs: frozenset[str] = parse_and_validate_langs(langs) self.langs: frozenset[str] = parse_and_validate_langs(langs)
self.mode: str = parse_and_validate_mode(mode) self.mode: str = parse_and_validate_mode(mode)
self.max_unhyphenated_len = max_unhyphenated_len self.max_unhyphenated_len = max_unhyphenated_len
@ -35,6 +35,7 @@ class Hyphenator:
self._load_language_resources_for_hyphenation() self._load_language_resources_for_hyphenation()
# Определяем символ переноса в зависимости от режима # Определяем символ переноса в зависимости от режима
self._split_code: str = SHY_ENTITIES['SHY'][0] if self.mode == MODE_UNICODE else SHY_ENTITIES['SHY'][1] self._split_code: str = SHY_ENTITIES['SHY'][0] if self.mode == MODE_UNICODE else SHY_ENTITIES['SHY'][1]
print(f"========={self.max_unhyphenated_len}===========")
def _load_language_resources_for_hyphenation(self): def _load_language_resources_for_hyphenation(self):
@ -87,12 +88,13 @@ class Hyphenator:
if len(word) <= self.max_unhyphenated_len or not any(self._is_vow(c) for c in word): if len(word) <= self.max_unhyphenated_len or not any(self._is_vow(c) for c in word):
# Если слово короткое или не содержит гласных, перенос не нужен # Если слово короткое или не содержит гласных, перенос не нужен
return word return word
print("слово:", word, " // mode:", self.mode, " // langs:", self.langs)
# 2. ОБНАРУЖЕНИЕ ЯЗЫКА И ПОДКЛЮЧЕНИЕ ЯЗЫКОВОЙ ЛОГИКИ # 2. ОБНАРУЖЕНИЕ ЯЗЫКА И ПОДКЛЮЧЕНИЕ ЯЗЫКОВОЙ ЛОГИКИ
# Поиск вхождения букв строки (слова) через `frozenset` -- O(1). Это быстрее регулярного выражения -- O(n) # Поиск вхождения букв строки (слова) через `frozenset` -- O(1). Это быстрее регулярного выражения -- O(n)
# 2.1. Проверяем RU # 2.1. Проверяем RU
if LANG_RU in self.langs and frozenset(word.upper()) <= self._ru_alphabet_upper: if LANG_RU in self.langs and frozenset(word.upper()) <= self._ru_alphabet_upper:
# Пользователь подключил русскую логику, и слово содержит только русские буквы # Пользователь подключил русскую логику, и слово содержит только русские буквы
print(f"#### Applying Russian rules to: {word}")
# Поиск допустимой позиции для переноса около заданного индекса # Поиск допустимой позиции для переноса около заданного индекса
def find_hyphen_point_ru(word_segment: str, start_idx: int) -> int: 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)] vow_indices = [i for i, char_w in enumerate(word_segment) if self._is_vow(char_w)]
@ -181,8 +183,11 @@ class Hyphenator:
hyphenated_word = self.hyp_in_word(word_to_process) hyphenated_word = self.hyp_in_word(word_to_process)
# ============= Для отладки (слова в которых появились переносы) ================== # ============= Для отладки (слова в которых появились переносы) ==================
print(f"hyp_in_text: '{word_to_process}'", end="")
if word_to_process != hyphenated_word: if word_to_process != hyphenated_word:
print(f"hyp_in_text: '{word_to_process}' -> '{hyphenated_word}'") print(f" -> '{hyphenated_word}'")
else:
print(" (no change)")
return hyphenated_word return hyphenated_word

View File

@ -1,6 +1,5 @@
from etpgrf.comutil import parse_and_validate_mode, parse_and_validate_langs from etpgrf.comutil import parse_and_validate_mode, parse_and_validate_langs
from etpgrf.hyphenation import Hyphenator from etpgrf.hyphenation import Hyphenator
import copy
# --- Основной класс Typographer --- # --- Основной класс Typographer ---
@ -8,37 +7,41 @@ class Typographer:
def __init__(self, def __init__(self,
langs: str | list[str] | tuple[str, ...] | frozenset[str] | None = None, langs: str | list[str] | tuple[str, ...] | frozenset[str] | None = None,
mode: str | None = None, mode: str | None = None,
hyphenation_rule: Hyphenator | None = None, # Перенос слов и параметры расстановки переносов hyphenation: Hyphenator | bool | None = True, # Перенос слов и параметры расстановки переносов
# glue_prepositions_rule: GluePrepositionsRule | None = None, # Для других правил # glue_prepositions_rule: GluePrepositionsRule | None = None, # Для других правил
# ... другие модули правил ... # ... другие модули правил ...
): ):
# --- Обработка и валидация параметра langs --- # A. --- Обработка и валидация параметра langs ---
self.langs: frozenset[str] = parse_and_validate_langs(langs) self.langs: frozenset[str] = parse_and_validate_langs(langs)
# B. --- Обработка и валидация параметра mode ---
# --- Обработка и валидация параметра mode ---
self.mode: str = parse_and_validate_mode(mode) self.mode: str = parse_and_validate_mode(mode)
print("Typographer: langs:", self.langs, "// mode:", self.mode) # Для отладки
# Сохраняем переданные модули правил # C. --- Инициализация правила переноса ---
if hyphenation_rule is not None: # Предпосылка: если вызвали типограф, значит, мы хотим обрабатывать текст и переносы тоже нужно расставлять.
# 1. Создаем поверхностную копию объекта hyphenation_rule. # А для специальных случаев, когда переносы не нужны, пусть не ленятся и делают `hyphenation=False`.
self.hyphenation_rule = copy.copy(hyphenation_rule) self.hyphenation: Hyphenator | None = None
# 2. Наследуем режим типографа, если он не задан в hyphenation_rule. if hyphenation is True or hyphenation is None:
if self.hyphenation_rule.mode is None: # 1. Создаем новый объект Hyphenator с заданными языками и режимом, а все остальное по умолчанию
self.hyphenation_rule.mode = self.mode self.hyphenation = Hyphenator(langs=self.langs, mode=self.mode)
# 2. Наследуем языки от типографа, если они не заданы в hyphenation_rule. elif isinstance(hyphenation, Hyphenator):
if self.hyphenation_rule.langs is None: # 2. Если hyphenation - это объект Hyphenator, то просто сохраняем его (и используем его langs и mode)
self.hyphenation_rule.langs = self.langs self.hyphenation = hyphenation
elif hyphenation is False:
# 3. Если hyphenation - False, то правило переноса выключено.
self.hyphenation = None
else: else:
self.hyphenation_rule = hyphenation_rule # 4. Если hyphenation что-то неведомое, то игнорируем его и правило переноса выключено
self.hyphenation = None
# D. --- Конфигурация других правил---
# Конвейер для обработки текста # Конвейер для обработки текста
def process(self, text: str) -> str: def process(self, text: str) -> str:
processed_text = text processed_text = text
if self.hyphenation_rule: if self.hyphenation is not None:
# Обработчик переносов (Hyphenator) активен. Обрабатываем текст... # Обработчик переносов (Hyphenator) активен. Обрабатываем текст...
processed_text = self.hyphenation_rule.hyp_in_text(processed_text) processed_text = self.hyphenation.hyp_in_text(processed_text)
# if self.glue_prepositions_rule: # if self.glue_prepositions_rule:
# processed_text = self.glue_prepositions_rule.hyp_in_text(processed_text, non_breaking_space_char=self._get_nbsp()) # processed_text = self.glue_prepositions_rule.hyp_in_text(processed_text, non_breaking_space_char=self._get_nbsp())

14
main.py
View File

@ -4,6 +4,9 @@ import etpgrf
if __name__ == '__main__': if __name__ == '__main__':
# --- Пример использования --- # --- Пример использования ---
print("\n--- Пример использования класса---\n") print("\n--- Пример использования класса---\n")
etpgrf.config.DEFAULT_HYP_MAX_LEN = 6
# Определяем пользовательские правила переносов # Определяем пользовательские правила переносов
hyphen_settings = etpgrf.Hyphenator(langs='ru', max_unhyphenated_len=8) hyphen_settings = etpgrf.Hyphenator(langs='ru', max_unhyphenated_len=8)
# Определяем пользовательские правила типографа # Определяем пользовательские правила типографа
@ -14,13 +17,14 @@ if __name__ == '__main__':
print(result, "\n\n") print(result, "\n\n")
hyphen_settings2 = etpgrf.Hyphenator(langs='en', max_unhyphenated_len=8) hyphen_settings2 = etpgrf.Hyphenator(langs='en', max_unhyphenated_len=8)
result = hyphen_settings2.hyp_in_text("frozenseter") result = hyphen_settings2.hyp_in_text("floccinaucinihilipilification")
print(result, "\n\n") print(result, "\n\n")
typo = etpgrf.Typographer(langs='ru', mode='mnemonic', hyphenation_rule=hyphen_settings) typo_ru = etpgrf.Typographer(langs='ru', mode='mixed', hyphenation=hyphen_settings)
result = typo.process(text="Какой-то длинный текст для проверки переносов. Перпердикюляция!") result = typo_ru.process(text="Какой-то длинный текст для проверки переносов. Перпердикюляция!")
print(result, "\n\n") print(result, "\n\n")
result = typo.process(text="Привет, frozenseter! Это <i>тестовый текст для проверки расстановки</i> переносов" typo_ru_en = etpgrf.Typographer(langs='ru-en', mode='mixed', hyphenation=True)
result = typo_ru_en.process(text="Расприветище, floccinaucinihilipilification. Это <i>тестовый текст для проверки расстановки</i> переносов"
" в словах. Миллион 100-метровошеих жирножирафов.") " в словах. Миллион 100-метровошеих жирножирафов.")
print(result, "\n\n") print(result, "\n\n")
@ -29,5 +33,5 @@ if __name__ == '__main__':
" чувствовать себя собой. <b>Мы&nbsp;не&nbsp;шьём одина&shy;ковые пальто. Мы шьём ваше. </b> Ниже&nbsp;—" " чувствовать себя собой. <b>Мы&nbsp;не&nbsp;шьём одина&shy;ковые пальто. Мы шьём ваше. </b> Ниже&nbsp;—"
" как устроен процесс заказа.</p>") " как устроен процесс заказа.</p>")
result = typo.process(text=txt) result = typo_ru.process(text=txt)
print(result, "\n\n") print(result, "\n\n")