mod: добавлены "компенсирующие" пробелы + немного оптимизации в конфигах.
This commit is contained in:
174
etpgrf/config.py
174
etpgrf/config.py
@@ -69,13 +69,45 @@ CHAR_ARROW_LR = '\u27f7' # Длинная двунаправленная ст
|
|||||||
CHAR_ARROW_L_LONG_DOUBLE = '\u27f8' # Длинная двойная стрелка влево
|
CHAR_ARROW_L_LONG_DOUBLE = '\u27f8' # Длинная двойная стрелка влево
|
||||||
CHAR_ARROW_R_LONG_DOUBLE = '\u27f9' # Длинная двойная стрелка вправо
|
CHAR_ARROW_R_LONG_DOUBLE = '\u27f9' # Длинная двойная стрелка вправо
|
||||||
CHAR_ARROW_LR_LONG_DOUBLE = '\u27fa' # Длинная двойная двунаправленная стрелка
|
CHAR_ARROW_LR_LONG_DOUBLE = '\u27fa' # Длинная двойная двунаправленная стрелка
|
||||||
CHAR_MIDDOT = '\u00b7' # Средняя точка (· иногда используется как знак умножения) / ·
|
CHAR_MIDDOT = '\u00b7' # Средняя точка (· иногда используется как знак умножения) / ·
|
||||||
|
# ПРОБЕЛЫ
|
||||||
|
CHAR_EN_SP = '\u2002' # Полужирный пробел (En Space) --  
|
||||||
|
CHAR_EM_SP = '\u2003' # Широкий пробел (Em Space) --  
|
||||||
|
CHAR_NUM_SP = '\u2007' # Цифровой пробел --  
|
||||||
|
CHAR_PUNT_SP = '\u2008' # Пунктуационный пробел --  
|
||||||
|
CHAR_HAIR_SP = '\u200A' # Толщина волоса (Hair Space) --  
|
||||||
|
CHAR_MED_SP = '\u205F' # Средний пробел (Medium Mathematical Space) --  
|
||||||
|
CHAR_NULL_SP = '\u200B' # Нулевой пробел (Zero Width Space)... в стандартах мнемоник путаница, и ее мнемоника ​
|
||||||
|
CHAR_THIN_NBSP = '\u202F' # Тонкий неразрывной пробел (Narrow No-Break Space) который, к сожалению, не имеет html-мнемоники
|
||||||
|
CHAR_ZWNJ = '\u200D' # Нулевая ширина (с объединением) (Zero Width Joiner) -- ‌
|
||||||
|
CHAR_EN_QUAD_SP = '\u2000' # Полукруглая шпация, ширина равна 1/2 от кегля (En Quad)
|
||||||
|
CHAR_EM_QUAD_SP = '\u2001' # Круглая шпация, ширина равна 1/1 (полный кегль), квадрат (Em Quad)
|
||||||
|
CHAR_THREE_PER_EM_SP = '\u2004' # «Толстый» пробел, ширина 1/3 от круглой шпации (Three-Per-Em Space) --  
|
||||||
|
CHAR_FOUR_PER_EM_SP = '\u2005' # Средний пробел, ширина 1/4 от круглой шпации (Four-Per-Em Space) --  
|
||||||
|
CHAR_SIX_PER_EM_SP = '\u2006' # «Тонкий» волосяной пробел, ширина 1/6 от круглой шпации (Six-Per-Em Space)
|
||||||
|
# ПРОСТО ЧАСТО ИСПОЛЬЗУЕМЫЕ СИМВОЛЫ, ДЛЯ ЭКОНОМИИ ПАМЯТИ (эфемерно, т.к. Python все равно бы оптимизировал, но для ясности и удобства):
|
||||||
|
CHAR_LPAR = '(' # Левая круглая скобка
|
||||||
|
CHAR_LSQB = '[' # Левая квадратная скобка
|
||||||
|
CHAR_LCUB = '{' # Левая фигурная скобка
|
||||||
|
CHAR_RPAR = ')' # Правая круглая скобка
|
||||||
|
CHAR_RSQB = ']' # Правая квадратная скобка
|
||||||
|
CHAR_RCUB = '}' # Правая фигурная скобка
|
||||||
|
CHAR_DOT = '.' # Точка
|
||||||
|
CHAR_COMMA = ',' # Запятая
|
||||||
|
CHAR_COLON = ':' # Двоеточие
|
||||||
|
# СЛУЖЕБНЫЕ СИМВОЛЫ (НЕ ДОЛЖНЫ ПРИНИМАТЬСЯ ВВОДОМ И НЕ ДОЛЖНЫ ВЫВОДИТЬСЯ, ИСПОЛЬЗУЮТСЯ ТОЛЬКО ВНУТРИ ПРОЦЕССОРОВ ДЛЯ ВРЕМЕННОЙ ЗАМЕНЫ ИЛИ РАЗДЕЛЕНИЯ):
|
||||||
CHAR_UNIT_SEPARATOR = '\u25F0' # Символ временный разделитель для составных единиц (◰), чтобы не уходить
|
CHAR_UNIT_SEPARATOR = '\u25F0' # Символ временный разделитель для составных единиц (◰), чтобы не уходить
|
||||||
# в "мертвый" цикл при замене на тонкий пробел. Можно взять любой редкий символом.
|
# в "мертвый" цикл при замене на тонкий пробел. Можно взять любой редкий символом.
|
||||||
CHAR_PLACEHOLDER = '\uFFFC' # Уникальная строка-заполнитель для защищенных тегов.
|
CHAR_PLACEHOLDER = '\uFFFC' # Уникальная строка-заполнитель для защищенных тегов.
|
||||||
CHAR_AMP_PLACEHOLDER = '\uFFFD' # Маркер-плейсхолдер для амперсанда (&), чтобы избежать его двойного кодирования в & при замене на мнемонику.
|
CHAR_AMP_PLACEHOLDER = '\uFFFD' # Маркер-плейсхолдер для амперсанда (&), чтобы избежать его двойного кодирования в & при замене на мнемонику.
|
||||||
CHAR_NODE_SEPARATOR = '\uFFFF' # Маркер границы текстовых узлов (Non-character).
|
CHAR_NODE_SEPARATOR = '\uFFFF' # Маркер границы текстовых узлов (Non-character).
|
||||||
|
|
||||||
|
# === КОНСТАНТЫ ДЛЯ САНИТИЗАЦИИ ===
|
||||||
|
# TODO: Их обработку (очистку) нужно добавить в модуль sanitization.py на входе.
|
||||||
|
CHARS_SYMBOLS_TO_BAN = frozenset([
|
||||||
|
CHAR_UNIT_SEPARATOR, CHAR_PLACEHOLDER, CHAR_AMP_PLACEHOLDER, CHAR_NODE_SEPARATOR
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
# === КОНСТАНТЫ ПСЕВДОГРАФИКИ ===
|
# === КОНСТАНТЫ ПСЕВДОГРАФИКИ ===
|
||||||
# Для простых замен "строка -> символ" используем список кортежей.
|
# Для простых замен "строка -> символ" используем список кортежей.
|
||||||
@@ -108,8 +140,8 @@ STR_TO_SYMBOL_REPLACEMENTS = [
|
|||||||
|
|
||||||
# === КОНСТАНТЫ ДЛЯ КОДИРОВАНИЯ HTML-МНЕМНОИКОВ ===
|
# === КОНСТАНТЫ ДЛЯ КОДИРОВАНИЯ HTML-МНЕМНОИКОВ ===
|
||||||
# --- ЧЕРНЫЙ СПИСОК: Символы, которые НИКОГДА не нужно кодировать в мнемоники ---
|
# --- ЧЕРНЫЙ СПИСОК: Символы, которые НИКОГДА не нужно кодировать в мнемоники ---
|
||||||
NEVER_ENCODE_CHARS = (frozenset(['!', '#', '%', '(', ')', '*', ',', '.', '/', ':', ';', '=', '?', '@',
|
NEVER_ENCODE_CHARS = (frozenset(['!', '#', '%', CHAR_LPAR, CHAR_RPAR, '*', CHAR_COMMA, CHAR_DOT, '/', CHAR_COLON, ';', '=', '?', '@',
|
||||||
'[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', '\n', '\t', '\r'])
|
CHAR_LSQB, '\\', CHAR_RSQB, '^', '_', '`', CHAR_LCUB, '|', CHAR_RCUB, '~', '\n', '\t', '\r'])
|
||||||
| RU_ALPHABET_FULL | EN_ALPHABET_FULL)
|
| RU_ALPHABET_FULL | EN_ALPHABET_FULL)
|
||||||
|
|
||||||
# 2. БЕЛЫЙ СПИСОК (ДЛЯ БЕЗОПАСНОСТИ):
|
# 2. БЕЛЫЙ СПИСОК (ДЛЯ БЕЗОПАСНОСТИ):
|
||||||
@@ -119,22 +151,25 @@ SAFE_MODE_CHARS_TO_MNEMONIC = frozenset([
|
|||||||
'<', '>', '&', '"', '\'',
|
'<', '>', '&', '"', '\'',
|
||||||
CHAR_SHY, # Мягкий перенос (Soft Hyphen) -- ­
|
CHAR_SHY, # Мягкий перенос (Soft Hyphen) -- ­
|
||||||
CHAR_NBSP, # Неразрывный пробел (Non-Breaking Space) --
|
CHAR_NBSP, # Неразрывный пробел (Non-Breaking Space) --
|
||||||
'\u2002', # Полужирный пробел (En Space) --  
|
CHAR_EN_SP, # Полужирный пробел (En Space) --  
|
||||||
'\u2003', # Широкий пробел (Em Space) --  
|
CHAR_EM_SP, # Широкий пробел (Em Space) --  
|
||||||
'\u2007', # Цифровой пробел --  
|
CHAR_NUM_SP, # Цифровой пробел --  
|
||||||
'\u2008', # Пунктуационный пробел --  
|
CHAR_PUNT_SP, # Пунктуационный пробел --  
|
||||||
CHAR_THIN_SP, # Межсимвольный пробел, тонкий пробел, шпация --  '
|
CHAR_THIN_SP, # Межсимвольный пробел, тонкий пробел, шпация --  '
|
||||||
'\u200A', # Толщина волоса (Hair Space) --  
|
CHAR_HAIR_SP, # Толщина волоса (Hair Space) --  
|
||||||
'\u200B', # Негативный пробел (Negative Space) -- ​
|
CHAR_NULL_SP, # Нулевой пробел (Zero Width Space)... в стандартах мнемоник путаница, и ее мнемоника ​
|
||||||
'\u200C', # Нулевая ширина (без объединения) (Zero Width Non-Joiner) -- ‍
|
'\u200C', # Нулевая ширина (без объединения) (Zero Width Non-Joiner) -- ‍
|
||||||
'\u200D', # Нулевая ширина (с объединением) (Zero Width Joiner) -- ‌
|
CHAR_ZWNJ, # Нулевая ширина (с объединением) (Zero Width Joiner) -- ‌
|
||||||
|
CHAR_THREE_PER_EM_SP, # «Толстый» пробел, ширина 1/3 от круглой шпации (Three-Per-Em Space) --  
|
||||||
|
CHAR_FOUR_PER_EM_SP, # Средний пробел, ширина 1/4 от круглой шпации (Four-Per-Em Space) --  
|
||||||
'\u200E', # Изменить направление текста на слева-направо (Left-to-Right Mark /LRE) -- ‎
|
'\u200E', # Изменить направление текста на слева-направо (Left-to-Right Mark /LRE) -- ‎
|
||||||
'\u200F', # Изменить направление текста направо-налево (Right-to-Left Mark /RLM) -- ‏
|
'\u200F', # Изменить направление текста направо-налево (Right-to-Left Mark /RLM) -- ‏
|
||||||
'\u2010', # Дефис (Hyphen) -- ‐
|
'\u2010', # Дефис (Hyphen) -- ‐
|
||||||
'\u205F', # Средний пробел (Medium Mathematical Space) --  
|
CHAR_MED_SP, # Средний пробел (Medium Mathematical Space) --  
|
||||||
'\u2060', # ⁠
|
'\u2060', # ⁠
|
||||||
'\u2062', # ⁢ -- для семантической разметки математических выражений
|
'\u2062', # ⁢ -- для семантической разметки математических выражений
|
||||||
'\u2063', # ⁣ -- для семантической разметки математических выражений
|
'\u2063', # ⁣ -- для семантической разметки математических выражений
|
||||||
|
|
||||||
])
|
])
|
||||||
|
|
||||||
# 3. СПИСОК ДЛЯ ЧИСЛОВОГО КОДИРОВАНИЯ: Символы без стандартного имени.
|
# 3. СПИСОК ДЛЯ ЧИСЛОВОГО КОДИРОВАНИЯ: Символы без стандартного имени.
|
||||||
@@ -149,6 +184,10 @@ ALWAYS_ENCODE_TO_NUMERIC_CHARS = frozenset([
|
|||||||
'\u20BD', # Знак русского рубля (₽)
|
'\u20BD', # Знак русского рубля (₽)
|
||||||
'\u20BE', # Знак грузинский лари (₾)
|
'\u20BE', # Знак грузинский лари (₾)
|
||||||
'\u20BF', # Знак биткоина (₿)
|
'\u20BF', # Знак биткоина (₿)
|
||||||
|
CHAR_THIN_NBSP, # Тонкий неразрывный пробел (Narrow No-Break Space) -- как   но с поведением (к сожалению, не имеет html-мнемоники)
|
||||||
|
CHAR_EN_QUAD_SP, # Полукруглая шпация, ширина равна 1/2 от кегля (En Quad)
|
||||||
|
CHAR_EM_QUAD_SP, # Круглая шпация, ширина равна 1/1 (полный кегль), квадрат (Em Quad)
|
||||||
|
CHAR_SIX_PER_EM_SP, # «Тонкий» волосяной пробел, ширина 1/6 от круглой шпации (Six-Per-Em Space)
|
||||||
])
|
])
|
||||||
|
|
||||||
# 4. СЛОВАРЬ ПРИОРИТЕТОВ: Кастомные и/или предпочитаемые мнемоники.
|
# 4. СЛОВАРЬ ПРИОРИТЕТОВ: Кастомные и/или предпочитаемые мнемоники.
|
||||||
@@ -605,7 +644,7 @@ def _build_translation_maps() -> dict[str, str]:
|
|||||||
# На его основе строим нашу карту для кодирования.
|
# На его основе строим нашу карту для кодирования.
|
||||||
encode_map = {}
|
encode_map = {}
|
||||||
|
|
||||||
# ШАГ 2: Высший приоритет. Загружаем наши кастомные правила.
|
# ШАГ 2: Высший приоритет. Загружаем кастомные правила.
|
||||||
encode_map.update(CUSTOM_ENCODE_MAP)
|
encode_map.update(CUSTOM_ENCODE_MAP)
|
||||||
|
|
||||||
# ШАГ 3: Следующий приоритет. Добавляем числовое кодирование.
|
# ШАГ 3: Следующий приоритет. Добавляем числовое кодирование.
|
||||||
@@ -697,37 +736,114 @@ HANGING_PUNCTUATION_MODES = frozenset([
|
|||||||
HANGING_PUNCTUATION_MODE_RIGHT,
|
HANGING_PUNCTUATION_MODE_RIGHT,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
# Пробелы ( символы-ищейки) которые могут использоваться как разделители "компенсационных сдвигов" для висячей пунктуации.
|
||||||
|
# Их соседство с висячими символами позволяет "компенсировать" их смещение относительно прилегающего символа.
|
||||||
|
HANGING_PUNCTUATION_SPACE_CHARS = frozenset([
|
||||||
|
' ', # обычный пробел
|
||||||
|
# CHAR_NBSP, # неразрывный пробел ( )
|
||||||
|
CHAR_SHY, # мягкий перенос (­)
|
||||||
|
CHAR_THIN_SP, # тонкий пробел ( )
|
||||||
|
CHAR_EN_QUAD_SP, # Полукруглая шпация, ширина равна 1/2 от кегля (En Quad)
|
||||||
|
CHAR_EM_QUAD_SP, # Круглая шпация, ширина равна 1/1 (полный кегль), квадрат (Em Quad)
|
||||||
|
CHAR_EN_SP, # EN-пробел (en space)
|
||||||
|
CHAR_EM_SP, # EM-пробел (em space)
|
||||||
|
CHAR_THREE_PER_EM_SP, # «Толстый» пробел, ширина 1/3 от круглой шпации (Three-Per-Em Space)
|
||||||
|
CHAR_FOUR_PER_EM_SP, # Средний пробел, ширина 1/4 от круглой шпации (Four-Per-Em Space)
|
||||||
|
CHAR_SIX_PER_EM_SP, # «Тонкий» волосяной пробел, ширина 1/6 от круглой шпации (Six-Per-Em Space)
|
||||||
|
CHAR_NUM_SP, # цифровой пробел (figure space)
|
||||||
|
CHAR_PUNT_SP, # пунктуационный пробел (punctuation space)
|
||||||
|
CHAR_HAIR_SP, # волосной пробел (hair space)
|
||||||
|
# CHAR_THIN_NBSP, # Тонкий неразрывной пробел (Narrow No-Break Space) который, к сожалению, не имеет html-мнемоники
|
||||||
|
CHAR_MED_SP, # средний пробел (medium space)
|
||||||
|
CHAR_NULL_SP, # нулевой пробел (zero width space)... в мнемонике ​
|
||||||
|
'\t', # табуляция
|
||||||
|
'\n', # перевод строки
|
||||||
|
'\r', # возврат каретки
|
||||||
|
'\u000b', # вертикальная табуляция
|
||||||
|
'\f' # перевод страницы
|
||||||
|
])
|
||||||
|
|
||||||
# 1. Набор символов, которые могут "висеть" слева
|
# 1. Набор символов, которые могут "висеть" слева
|
||||||
|
# ВАЖНО: кавычки второго уровня (CHAR_EN_QUOT2_OPEN = '„' и CHAR_RU_QUOT2_OPEN = '„') НЕ ВКЛЮЧЕНЫ,
|
||||||
|
# т.к. CHAR_RU_QUOT2_CLOSE == CHAR_EN_QUOT1_OPEN и невозможно отличить закрывающую кавычку (ru)
|
||||||
|
# от открывающей кавычки (en) и однозначно решить к какую сторону делать вывешивание.
|
||||||
|
# TODO: в будущем можно попробовать определять это по прилегающему пробелу (слева или справа).
|
||||||
HANGING_PUNCTUATION_LEFT_CHARS = frozenset([
|
HANGING_PUNCTUATION_LEFT_CHARS = frozenset([
|
||||||
CHAR_RU_QUOT1_OPEN, # «
|
CHAR_RU_QUOT1_OPEN, # «
|
||||||
CHAR_EN_QUOT1_OPEN, # “
|
CHAR_EN_QUOT1_OPEN, # “
|
||||||
'(', '[', '{',
|
CHAR_LPAR, # (
|
||||||
|
CHAR_LSQB, # [
|
||||||
|
CHAR_LCUB, # {
|
||||||
])
|
])
|
||||||
|
|
||||||
# 2. Набор символов, которые могут "висеть" справа
|
# 2. Набор символов, которые могут "висеть" справа
|
||||||
HANGING_PUNCTUATION_RIGHT_CHARS = frozenset([
|
HANGING_PUNCTUATION_RIGHT_CHARS = frozenset([
|
||||||
CHAR_RU_QUOT1_CLOSE, # »
|
CHAR_RU_QUOT1_CLOSE, # »
|
||||||
CHAR_EN_QUOT1_CLOSE, # ”
|
CHAR_EN_QUOT1_CLOSE, # ”
|
||||||
')', ']', '}',
|
CHAR_RPAR, # )
|
||||||
'.', ',', ':',
|
CHAR_RSQB, # ]
|
||||||
|
CHAR_RCUB, # }
|
||||||
|
CHAR_DOT, # .
|
||||||
|
CHAR_COMMA, # ,
|
||||||
|
CHAR_COLON, # :
|
||||||
])
|
])
|
||||||
|
|
||||||
# 3. Словарь, сопоставляющий символ с его CSS-классом
|
# 3. Словарь, сопоставляющий символ с его CSS-классом
|
||||||
HANGING_PUNCTUATION_CLASSES = {
|
HANGING_PUNCTUATION_SYMBOLS_CLASSES = {
|
||||||
# Левая пунктуация: все классы начинаются с 'etp-l'
|
# Левая пунктуация: все классы начинаются с 'etp-l'
|
||||||
CHAR_RU_QUOT1_OPEN: 'etp-laquo',
|
CHAR_RU_QUOT1_OPEN: 'etp-laquo', # ` «` -- левая открывающая кавычка-ёлочка
|
||||||
CHAR_EN_QUOT1_OPEN: 'etp-ldquo',
|
CHAR_EN_QUOT1_OPEN: 'etp-ldquo', # ` “` -- левая открывающая кавычка-лапка
|
||||||
'(': 'etp-lpar',
|
CHAR_LPAR: 'etp-lpar', # ` (` -- левая открывающая скобка
|
||||||
'[': 'etp-lsqb',
|
CHAR_LSQB: 'etp-lsqb', # ` [` -- левая открывающая квадратная скобка
|
||||||
'{': 'etp-lcub',
|
CHAR_LCUB: 'etp-lcub', # ` {` -- левая открывающая фигурная скобка
|
||||||
# Правая пунктуация: все классы начинаются с 'etp-r'
|
# Правая пунктуация: все классы начинаются с 'etp-r'
|
||||||
CHAR_RU_QUOT1_CLOSE: 'etp-raquo',
|
CHAR_RU_QUOT1_CLOSE: 'etp-raquo', # `» ` -- правая закрывающая кавычка-ёлочка
|
||||||
CHAR_EN_QUOT1_CLOSE: 'etp-rdquo',
|
CHAR_EN_QUOT1_CLOSE: 'etp-rdquo', # `” ` -- правая закрывающая кавычка-лапка
|
||||||
')': 'etp-rpar',
|
CHAR_RPAR: 'etp-rpar', # `) ` -- правая закрывающая скобка
|
||||||
']': 'etp-rsqb',
|
CHAR_RSQB: 'etp-rsqb', # `] ` -- правая закрывающая квадратная скобка
|
||||||
'}': 'etp-rcub',
|
CHAR_RCUB: 'etp-rcub', # `} ` -- правая закрывающая фигурная скобка
|
||||||
'.': 'etp-r-dot',
|
CHAR_DOT: 'etp-r-dot', # `. ` -- точка (обычно в конце предложения и висит справа)
|
||||||
',': 'etp-r-comma',
|
CHAR_COMMA: 'etp-r-comma', # `, ` -- запятая (обычно висит справа)
|
||||||
':': 'etp-r-colon',
|
CHAR_COLON: 'etp-r-colon', # `: ` -- двоеточие (обычно висит справа)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 4. Словарь, сопоставляющий классам висячей пунктуации классы для компенсационных пробелов
|
||||||
|
HANGING_PUNCTUATION_SPACE_CLASSES = {
|
||||||
|
'left': {
|
||||||
|
# Для левой пунктуации (компенсационный пробел слева от висячей пунктуации)
|
||||||
|
CHAR_RU_QUOT1_OPEN: 'etp-sp-laquo', # ` «` -- для пробела пред открывающей кавычкой-ёлочкой
|
||||||
|
CHAR_EN_QUOT1_OPEN: 'etp-sp-ldquo', # ` “` -- для пробела пред открывающей кавычкой-лапкой
|
||||||
|
CHAR_LPAR: 'etp-sp-lpar', # ` (` -- для пробела пред левой открывающей скобкой
|
||||||
|
CHAR_LSQB: 'etp-sp-lsqb', # ` [` -- для пробела пред левой открывающей квадратной скобкой
|
||||||
|
CHAR_LCUB: 'etp-sp-lcub', # ` {` -- для пробела пред левой открывающей фигурной скобкой
|
||||||
|
},
|
||||||
|
'right': {
|
||||||
|
# Для правой пунктуации (компенсационный пробел справа от висячей пунктуации)
|
||||||
|
CHAR_RU_QUOT1_CLOSE: 'etp-sp-raquo', # `» ` -- для пробела после закрывающей кавычки-ёлочки
|
||||||
|
CHAR_EN_QUOT1_CLOSE: 'etp-sp-rdquo', # `” ` -- для пробела после закрывающей кавычки-лапки
|
||||||
|
CHAR_RPAR: 'etp-sp-rpar', # `) ` -- для пробела после правой закрывающей скобки
|
||||||
|
CHAR_RSQB: 'etp-sp-rsqb', # `] ` -- для пробела после правой закрывающей квадратной скобки
|
||||||
|
CHAR_RCUB: 'etp-sp-rcub', # `} ` -- для пробела после правой закрывающей фигурной скобки
|
||||||
|
CHAR_DOT: 'etp-sp-r-dot', # `. ` -- для пробела после точки
|
||||||
|
CHAR_COMMA: 'etp-sp-r-comma', # `, ` -- для пробела после запятой
|
||||||
|
CHAR_COLON: 'etp-sp-r-colon', # `: ` -- для пробела после двоеточия
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# 5. Набор пробелов (неразрывные) которые ОТМЕНЯЮТ висячую пунктуацию у прилегающего символа. Т.к. это неразрывный
|
||||||
|
# пробел, то символ не может "висеть" в принципе, он "прилеплен" к соседу и не может от него отрываться
|
||||||
|
HANGING_CANCELLATION_SP = frozenset([
|
||||||
|
CHAR_NBSP, # неразрывный пробел ( )
|
||||||
|
CHAR_ZWNJ, # нулевой неразрывный пробел (zero width non-joiner, ‌)
|
||||||
|
CHAR_THIN_NBSP, # узкий неразрывной пробел (narrow no-break space)
|
||||||
|
])
|
||||||
|
|
||||||
|
HANGING_PUNCTUATION_SPACE_CLASSES_FLAT = {
|
||||||
|
**HANGING_PUNCTUATION_SPACE_CLASSES['left'],
|
||||||
|
**HANGING_PUNCTUATION_SPACE_CLASSES['right'],
|
||||||
|
}
|
||||||
|
|
||||||
|
HANGING_PUNCTUATION_CLASSES = {
|
||||||
|
**HANGING_PUNCTUATION_SYMBOLS_CLASSES,
|
||||||
|
**HANGING_PUNCTUATION_SPACE_CLASSES_FLAT,
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from bs4 import BeautifulSoup, NavigableString, Tag
|
|||||||
from .config import (
|
from .config import (
|
||||||
HANGING_PUNCTUATION_LEFT_CHARS,
|
HANGING_PUNCTUATION_LEFT_CHARS,
|
||||||
HANGING_PUNCTUATION_RIGHT_CHARS,
|
HANGING_PUNCTUATION_RIGHT_CHARS,
|
||||||
HANGING_PUNCTUATION_CLASSES,
|
HANGING_PUNCTUATION_SYMBOLS_CLASSES,
|
||||||
HANGING_PUNCTUATION_MODE_LEFT,
|
HANGING_PUNCTUATION_MODE_LEFT,
|
||||||
HANGING_PUNCTUATION_MODE_RIGHT,
|
HANGING_PUNCTUATION_MODE_RIGHT,
|
||||||
)
|
)
|
||||||
@@ -47,7 +47,7 @@ class HangingPunctuationProcessor:
|
|||||||
# Предварительно фильтруем карту классов, оставляя только активные символы
|
# Предварительно фильтруем карту классов, оставляя только активные символы
|
||||||
self.char_to_class = {
|
self.char_to_class = {
|
||||||
char: cls
|
char: cls
|
||||||
for char, cls in HANGING_PUNCTUATION_CLASSES.items()
|
for char, cls in HANGING_PUNCTUATION_SYMBOLS_CLASSES.items()
|
||||||
if char in self.active_chars
|
if char in self.active_chars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
import logging
|
import logging
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from .config import (SANITIZE_ALL_HTML, SANITIZE_ETPGRF, SANITIZE_NONE,
|
from .config import (SANITIZE_ALL_HTML, SANITIZE_ETPGRF, SANITIZE_NONE,
|
||||||
HANGING_PUNCTUATION_CLASSES, PROTECTED_HTML_TAGS)
|
HANGING_PUNCTUATION_CLASSES, PROTECTED_HTML_TAGS,
|
||||||
|
HANGING_PUNCTUATION_SYMBOLS_CLASSES,
|
||||||
|
HANGING_PUNCTUATION_SPACE_CLASSES_FLAT)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -27,8 +29,10 @@ class SanitizerProcessor:
|
|||||||
|
|
||||||
# Оптимизация: заранее готовим CSS-селектор для поиска висячей пунктуации
|
# Оптимизация: заранее готовим CSS-селектор для поиска висячей пунктуации
|
||||||
if self.mode == SANITIZE_ETPGRF:
|
if self.mode == SANITIZE_ETPGRF:
|
||||||
# Собираем уникальные классы
|
# Собираем уникальные классы из отдельных коллекций (чтобы избежать пустого селектора)
|
||||||
unique_classes = sorted(list(frozenset(HANGING_PUNCTUATION_CLASSES.values())))
|
symbol_classes = set(HANGING_PUNCTUATION_SYMBOLS_CLASSES.values())
|
||||||
|
space_classes = set(HANGING_PUNCTUATION_SPACE_CLASSES_FLAT.values())
|
||||||
|
unique_classes = sorted(symbol_classes | space_classes)
|
||||||
# Формируем селектор вида: span.class1, span.class2, ...
|
# Формируем селектор вида: span.class1, span.class2, ...
|
||||||
# Это позволяет использовать нативный парсер (lxml) для поиска, что намного быстрее python-лямбд.
|
# Это позволяет использовать нативный парсер (lxml) для поиска, что намного быстрее python-лямбд.
|
||||||
self._etp_selector = ", ".join(f"span.{cls}" for cls in unique_classes)
|
self._etp_selector = ", ".join(f"span.{cls}" for cls in unique_classes)
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ ETPGRF_SANITIZE_TEST_CASES = [
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
"complex_case", "Сложный случай с несколькими разными span'ами",
|
"complex_case", "Сложный случай с несколькими разными span'ами",
|
||||||
'<h1><span class="etp-laquo">«</span>Title<span class="etp-raquo">»</span></h1>\n<p>And <span class="note">note</span>.</p>',
|
'<h1><span class="etp-laquo">«</span>Title<span class="etp-raquo">»</span></h1>\n'
|
||||||
|
'<p>And <span class="note">note</span>.</p>',
|
||||||
'<h1>«Title»</h1>\n<p>And <span class="note">note</span>.</p>'
|
'<h1>«Title»</h1>\n<p>And <span class="note">note</span>.</p>'
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user