# etpgrf/quotes.py # Модуль для расстановки кавычек в тексте import regex import logging from .config import LANG_RU, LANG_EN, RU_QUOT1_OPEN, RU_QUOT1_CLOSE, EN_QUOT1_OPEN, EN_QUOT1_CLOSE, \ RU_QUOT2_OPEN, RU_QUOT2_CLOSE, EN_QUOT2_OPEN, EN_QUOT2_CLOSE from .comutil import parse_and_validate_langs # --- Настройки логирования --- logger = logging.getLogger(__name__) # Определяем стили кавычек для разных языков # Формат: (('открывающая_ур1', 'закрывающая_ур1'), ('открывающая_ур2', 'закрывающая_ур2')) _QUOTE_STYLES = { LANG_RU: ((RU_QUOT1_OPEN, RU_QUOT1_CLOSE), (RU_QUOT2_OPEN, RU_QUOT2_CLOSE)), LANG_EN: ((EN_QUOT1_OPEN, EN_QUOT1_CLOSE), (EN_QUOT2_OPEN, EN_QUOT2_CLOSE)), } class QuotesProcessor: """ Обрабатывает прямые кавычки ("), превращая их в типографские в зависимости от языка и контекста. """ def __init__(self, langs: str | list[str] | tuple[str, ...] | frozenset[str] | None = None): self.langs = parse_and_validate_langs(langs) # Выбираем стиль кавычек на основе первого поддерживаемого языка self.open_quote = '"' self.close_quote = '"' for lang in self.langs: if lang in _QUOTE_STYLES: self.open_quote = _QUOTE_STYLES[lang][0][0] self.close_quote = _QUOTE_STYLES[lang][0][1] logger.debug( f"QuotesProcessor: выбран стиль кавычек для языка '{lang}': '{self.open_quote}...{self.close_quote}'") break # Используем стиль первого найденного языка # Паттерн для открывающей кавычки: " перед буквой/цифрой, # которой предшествует пробел, начало строки или открывающая скобка. # (?<=^|\s|[\(\[„\"‘\']) - "просмотр назад" на начало строки... ищет пробел \s или знак из набора ([„"‘' # (?=\p{L}) - "просмотр вперед" на букву \p{L} (но не цифру). self._opening_quote_pattern = regex.compile(r'(?<=^|\s|[\(\[„\"‘\'])\"(?=\p{L})') # self._opening_quote_pattern = regex.compile(r'(?<=^|\s|\p{Pi}|["\'\(\)])\"(?=\p{L})') # Паттерн для закрывающей кавычки: " после буквы/цифры, # за которой следует пробел, пунктуация или конец строки. # (?<=\p{L}|[?!…]) - "просмотр назад" на букву или ?!… # (?=\s|[.,;:!?\)\"»”’]|\Z) - "просмотр вперед" на пробел, пунктуацию или конец строки (\Z). self._closing_quote_pattern = regex.compile(r'(?<=\p{L}|[?!…])\"(?=\s|[\.,;:!?\)\]»”’\"\']|\Z)') # self._closing_quote_pattern = regex.compile(r'(?<=\p{L}|\p{N})\"(?=\s|[\.,;:!?\)\"»”’]|\Z)') # self._closing_quote_pattern = regex.compile(r'(?<=\p{L}|[?!…])\"(?=\s|[\p{Po}\p{Pf}"\']|\Z)') def process(self, text: str) -> str: """ Применяет правила замены кавычек к тексту. """ if '"' not in text: # Быстрый выход, если в тексте нет прямых кавычек return text processed_text = text # 1. Заменяем открывающие кавычки # Заменяем только найденную кавычку, так как просмотр вперед не захватывает символы. processed_text = self._opening_quote_pattern.sub(self.open_quote, processed_text) # 2. Заменяем закрывающие кавычки processed_text = self._closing_quote_pattern.sub(self.close_quote, processed_text) return processed_text