571 lines
36 KiB
Python
571 lines
36 KiB
Python
# etpgrf/conf.py
|
||
# Настройки по умолчанию и "источник правды" для типографа etpgrf
|
||
from html import entities
|
||
|
||
# === КОНФИГУРАЦИИ ===
|
||
# Режимы "отдачи" результатов обработки
|
||
MODE_UNICODE = "unicode"
|
||
MODE_MNEMONIC = "mnemonic"
|
||
MODE_MIXED = "mixed"
|
||
|
||
# Языки, поддерживаемые библиотекой
|
||
LANG_RU = 'ru' # Русский
|
||
LANG_RU_OLD = 'ruold' # Русская дореволюционная орфография
|
||
LANG_EN = 'en' # Английский
|
||
SUPPORTED_LANGS = frozenset([LANG_RU, LANG_RU_OLD, LANG_EN])
|
||
DEFAULT_LANGS = (LANG_RU, LANG_EN) # Языки по умолчанию
|
||
|
||
# === ИСТОЧНИК ПРАВДЫ ===
|
||
# --- Базовые алфавиты: Эти константы используются как для правил переноса, так и для правил кодирования ---
|
||
|
||
# Русский алфавит
|
||
RU_VOWELS_UPPER = frozenset(['А', 'О', 'И', 'Е', 'Ё', 'Э', 'Ы', 'У', 'Ю', 'Я'])
|
||
RU_CONSONANTS_UPPER = frozenset(['Б', 'В', 'Г', 'Д', 'Ж', 'З', 'К', 'Л', 'М', 'Н', 'П', 'Р', 'С', 'Т', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ'])
|
||
RU_J_SOUND_UPPER = frozenset(['Й'])
|
||
RU_SIGNS_UPPER = frozenset(['Ь', 'Ъ'])
|
||
RU_ALPHABET_UPPER = RU_VOWELS_UPPER | RU_CONSONANTS_UPPER | RU_J_SOUND_UPPER | RU_SIGNS_UPPER
|
||
RU_ALPHABET_LOWER = frozenset([char.lower() for char in RU_ALPHABET_UPPER])
|
||
RU_ALPHABET_FULL = RU_ALPHABET_UPPER | RU_ALPHABET_LOWER
|
||
|
||
# Английский алфавит
|
||
EN_VOWELS_UPPER = frozenset(['A', 'E', 'I', 'O', 'U', 'Æ', 'Œ'])
|
||
EN_CONSONANTS_UPPER = frozenset(['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'])
|
||
EN_ALPHABET_UPPER = EN_VOWELS_UPPER | EN_CONSONANTS_UPPER
|
||
EN_ALPHABET_LOWER = frozenset([char.lower() for char in EN_ALPHABET_UPPER])
|
||
EN_ALPHABET_FULL = EN_ALPHABET_UPPER | EN_ALPHABET_LOWER
|
||
|
||
# --- Специальные символы ---
|
||
NBSP_CHAR = '\u00A0' # Неразрывный пробел ( )
|
||
SHY_CHAR = '\u00AD' # Мягкий перенос (­)
|
||
RU_QUOT1_OPEN = '«'
|
||
RU_QUOT1_CLOSE = '»'
|
||
RU_QUOT2_OPEN = '„'
|
||
RU_QUOT2_CLOSE = '“'
|
||
EN_QUOT1_OPEN = '“'
|
||
EN_QUOT1_CLOSE = '”'
|
||
EN_QUOT2_OPEN = '‘'
|
||
EN_QUOT2_CLOSE = '’'
|
||
|
||
# === КОНСТАНТЫ ДЛЯ КОДИРОВАНИЯ HTML-МНЕМНОИКОВ ===
|
||
# --- ЧЕРНЫЙ СПИСОК: Символы, которые НИКОГДА не нужно кодировать в мнемоники ---
|
||
NEVER_ENCODE_CHARS = (frozenset(['!', '#', '%', '(', ')', '*', ',', '.', '/', ':', ';', '=', '?', '@',
|
||
'[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', '\n', '\t', '\r'])
|
||
| RU_ALPHABET_FULL | EN_ALPHABET_FULL)
|
||
|
||
# 2. БЕЛЫЙ СПИСОК (ДЛЯ БЕЗОПАСНОСТИ):
|
||
# Символы, которые ВСЕГДА должны превращаться в мнемоники в "безопасных" режимах вывода. Сюда добавлены символы,
|
||
# которые не видны, на глаз и не отличимы друг от друга в обычном тексте, или очень специфичные
|
||
SAFE_MODE_CHARS_TO_MNEMONIC = frozenset([
|
||
'<', '>', '&', '"', '\'',
|
||
SHY_CHAR, # Мягкий перенос (Soft Hyphen) -- ­
|
||
NBSP_CHAR, # Неразрывный пробел (Non-Breaking Space) --
|
||
'\u2002', # Полужирный пробел (En Space) --  
|
||
'\u2003', # Широкий пробел (Em Space) --  
|
||
'\u2007', # Цифровой пробел --  
|
||
'\u2008', # Пунктуационный пробел --  
|
||
'\u2009', # Межсимвольный пробел --  '
|
||
'\u200A', # Толщина волоса (Hair Space) --  
|
||
'\u200B', # Негативный пробел (Negative Space) -- ​
|
||
'\u200C', # Нулевая ширина (без объединения) (Zero Width Non-Joiner) -- ‍
|
||
'\u200D', # Нулевая ширина (с объединением) (Zero Width Joiner) -- ‌
|
||
'\u200E', # Изменить направление текста на слева-направо (Left-to-Right Mark /LRE) -- ‎
|
||
'\u200F', # Изменить направление текста направо-налево (Right-to-Left Mark /RLM) -- ‏
|
||
'\u2010', # Дефис (Hyphen) -- ‐
|
||
'\u205F', # Средний пробел (Medium Mathematical Space) --  
|
||
'\u2060', # ⁠
|
||
'\u2062', # ⁢ -- для семантической разметки математических выражений
|
||
'\u2063', # ⁣ -- для семантической разметки математических выражений
|
||
])
|
||
|
||
# 3. СПИСОК ДЛЯ ЧИСЛОВОГО КОДИРОВАНИЯ: Символы без стандартного имени.
|
||
ALWAYS_ENCODE_TO_NUMERIC_CHARS = frozenset([
|
||
'\u058F', # Знак армянского драма (֏)
|
||
'\u20BD', # Знак русского рубля (₽)
|
||
'\u20B4', # Знак украинской гривны (₴)
|
||
'\u20B8', # Знак казахстанского тенге (₸)
|
||
'\u20B9', # Знак индийской рупии (₹)
|
||
'\u20BC', # Знак азербайджанского маната
|
||
'\u20BE', # Знак грузинский лари (₾)
|
||
])
|
||
|
||
# 4. СЛОВАРЬ ПРИОРИТЕТОВ: Кастомные и/или предпочитаемые мнемоники.
|
||
# Некоторые utf-символы имеют несколько мнемоник, а значит для таких символов преобразование
|
||
# в из utf во html-мнемоники может иметь несколько вариантов. Словарь приоритетов задает предпочтительное
|
||
# преобразование. Эти правила применяются в последнюю очередь и имеют наивысший приоритет,
|
||
# гарантируя предсказуемый результат для символов с несколькими именами.
|
||
#
|
||
# Также можно использовать для создания исключений из "черного списка" NEVER_ENCODE_CHARS.
|
||
CUSTOM_ENCODE_MAP = {
|
||
# '\u2010': '‐', # Для \u2010 всегда предпочитаем ‐, а не ‐
|
||
# # Исключения для букв, которые есть в алфавитах, но должны кодироваться (для обеспечения консистентности):
|
||
# # 'Æ': 'Æ',
|
||
# # 'Œ': 'Œ',
|
||
# # 'æ': 'æ',
|
||
# # 'œ': 'œ',
|
||
# '\u002a': '*', # * / * / *
|
||
# '\u005b': '[', # [ / [ / [
|
||
# '\u005d': ']', # ] / ] / ]
|
||
# '\u005f': '_', # _ / _ / _
|
||
# '\u007b': '{', # { / { / {
|
||
# '\u007d': '}', # } / } / }
|
||
# '\u007c': '|', # | / | / | / |
|
||
# '\u0026': '&', # & / & / &
|
||
# NBSP_CHAR: ' ', # / /  
|
||
'\u0022': '"', # " / " / "
|
||
'\u0026': '&', # & / & / &
|
||
'\u003e': '>', # > / > / >
|
||
'\u003c': '<', # < / < / <
|
||
'\u00ae': '®', # ® / ® / ® / ®
|
||
'\u00b7': '·', # · / · / · / ·
|
||
'\u0060': '`', # ` / ` / `
|
||
'\u00a8': '¨', # ¨ / ¨ / ¨ / ¨ / ¨
|
||
'\u00b1': '±', # ± / ± / ±
|
||
'\u00bd': '½', # ½ / ½ / ½
|
||
'\u00af': '¯', # ¯ / ¯ / ¯
|
||
'\u201a': '‚', # ‚ / ‚ / ‚
|
||
'\u223e': '∾', # ∾ / ∾ / ∾
|
||
'\u2207': '∇', # ∇ / ∇ / ∇
|
||
'\u2061': '⁡', # / ⁡ / ⁡
|
||
'\u2221': '∡', # ∡ / ∡ / ∡
|
||
'\u2248': '≈', # ≈ / ≈ / ≈ / ≈ / ≈ / ≈
|
||
'\u224a': '≊', # ≊ / ≊ / ≊
|
||
'\u2254': '≔', # ≔ / ≔ / ≔ / ≔
|
||
'\u224d': '≍', # ≍ / ≍ / ≍
|
||
'\u2233': '∳', # ∳ / ∳ / ∳
|
||
'\u224c': '≌', # ≌ / ≌ / ≌
|
||
'\u03f6': '϶', # ϶ / ϶ / ϶
|
||
'\u2035': '‵', # ‵ / ‵ / ‵
|
||
'\u223d': '∽', # ∽ / ∽ / ∽
|
||
'\u22cd': '⋍', # ⋍ / ⋍ / ⋍
|
||
'\u2216': '∖', # ∖ / ∖ / ∖ / ∖ / ∖ / ∖
|
||
'\u2306': '⌆', # ⌆ / ⌆ / ⌆
|
||
'\u2305': '⌅', # ⌅ / ⌅ / ⌅
|
||
'\u23b5': '⎵', # ⎵ / ⎵ / ⎵
|
||
'\u2235': '∵', # ∵ / ∵ / ∵ / ∵
|
||
'\u212c': 'ℬ', # ℬ / ℬ / ℬ / ℬ
|
||
'\u2264': '≤', # ≤ / ≤ / ≤
|
||
'\u226c': '≬', # ≬ / ≬ / ≬
|
||
'\u22c2': '⋂', # ⋂ / ⋂ / ⋂ / ⋂
|
||
'\u25ef': '◯', # ◯ / ◯ / ◯
|
||
'\u22c3': '⋃', # ⋃ / ⋃ / ⋃ / ⋃
|
||
'\u2a00': '⨀', # ⨀ / ⨀ / ⨀
|
||
'\u2a01': '⨁', # ⨁ / ⨁ / ⨁
|
||
'\u2a02': '⨂', # ⨂ / ⨂ / ⨂
|
||
'\u2a06': '⨆', # ⨆ / ⨆ / ⨆
|
||
'\u2605': '★', # ★ / ★ / ★
|
||
'\u25bd': '▽', # ▽ / ▽ / ▽
|
||
'\u25b3': '△', # △ / △ / △
|
||
'\u2a04': '⨄', # ⨄ / ⨄ / ⨄
|
||
'\u22c1': '⋁', # ⋁ / ⋁ / ⋁ / ⋁
|
||
'\u22c0': '⋀', # ⋀ / ⋀ / ⋀ / $bigwedge;
|
||
'\u2227': '∧', # ∧ / ∧ / ∧
|
||
'\u290d': '⤍', # ⤍ / ⤍ / ⤍
|
||
'\u29eb': '⧫', # ⧫ / ⧫ / ⧫
|
||
'\u25ca': '◊', # ◊ / ◊ / &lozenge
|
||
'\u25aa': '▪', # ▪ / ▪ / ▪ / ▪ / ▪
|
||
'\u25b4': '▴', # ▴ / ▴ / ▴
|
||
'\u25be': '▾', # ▾ / ▾ / ▾
|
||
'\u25c2': '◂', # ◂ / ◂ / ◂
|
||
'\u25b8': '▸', # ▸ / ▸ / ▸
|
||
'\u22a5': '⊥', # ⊥ / ⊥ / ⊥ / ⊥ / ⊥
|
||
'\u2500': '─', # ─ / ─ / ─
|
||
'\u229f': '⊟', # ⊟ / ⊟ / ⊟
|
||
'\u229e': '⊞', # ⊞ / ⊞ / ⊞
|
||
'\u22a0': '⊠', # ⊠ / ⊠ / ⊠
|
||
'\u02d8': '˘', # ˘ / ˘ / ˘
|
||
'\u224e': '≎', # ≎ / ≎ / ≎ / ≎
|
||
'\u224f': '≏', # ≏ / ≏ / ≏ / ≏
|
||
'\u2145': 'ⅅ', # ⅅ / ⅅ / ⅅ
|
||
'\u02c7': 'ˇ', # ˇ / ˇ / ˇ
|
||
'\u212d': 'ℭ', # ℭ / ℭ / ℭ
|
||
'\u2713': '✓', # ✓ / ✓ / ✓
|
||
'\u2257': '≗', # ≗ / ≗ / ≗
|
||
'\u21ba': '↺', # ↺ / ↺ / ↺
|
||
'\u21bb': '↻', # ↻ / ↻ / ↻
|
||
'\u229b': '⊛', # ⊛ / ⊛ / ⊛
|
||
'\u229a': '⊚', # ⊚ / ⊚ / ⊚
|
||
'\u229d': '⊝', # ⊝ / ⊝ / ⊝
|
||
'\u2299': '⊙', # ⊙ / ⊙ / ⊙
|
||
'\u2200': '∀', # ∀ / ∀ / ∀
|
||
'\u24c8': 'Ⓢ', # Ⓢ / Ⓢ / Ⓢ
|
||
'\u2296': '⊖', # ⊖ / ⊖ / ⊖
|
||
'\u2232': '∲', # ∲ / ∲ / ∲
|
||
'\u201d': '”', # ” / ” / ” / ”
|
||
'\u2019': '’', # ’ / ’ / ’ / ’
|
||
'\u2237': '∷', # ∷ / ∷ / ∷
|
||
'\u2201': '∁', # ∁ / ∁ / ∁
|
||
'\u2218': '∘', # ∘ / ∘ / ∘
|
||
'\u2102': 'ℂ', # ℂ / ℂ / ℂ
|
||
'\u222f': '∯', # ∯ / ∯ / ∯
|
||
'\u222e': '∮', # ∮ / ∮ / ∮ / ∮
|
||
'\u2210': '∐', # ∐ / ∐ / ∐
|
||
'\u22de': '⋞', # ⋞ / ⋞ / ⋞
|
||
'\u22df': '⋟', # ⋟ / ⋟ / ⋟
|
||
'\u21b6': '↶', # ↶ / ↶ / ↶
|
||
'\u21b7': '↷', # ↷ / ↷ / ↷
|
||
'\u22ce': '⋎', # ⋎ / ⋎ / ⋎
|
||
'\u22cf': '⋏', # ⋏ / ⋏ / ⋏
|
||
'\u2010': '‐', # ‐ / ‐ / ‐
|
||
'\u2ae4': '⫤', # ⫤ / ⫤ / ⫤
|
||
'\u22a3': '⊣', # ⊣ / ⊣ / ⊣
|
||
'\u290f': '⤏', # ⤏ / ⤏ / ⤏
|
||
'\u02dd': '˝', # ˝ / ˝ / ˝
|
||
'\u2146': 'ⅆ', # ⅆ / ⅆ / ⅆ
|
||
'\u21ca': '⇊', # ⇊ / ⇊ / ⇊
|
||
'\u2a77': '⩷', # ⩷ / ⩷ / ⩷
|
||
'\u21c3': '⇃', # ⇃ / ⇃ / ⇃ / ⇃
|
||
'\u21c2': '⇂', # ⇂ / ⇂ / ⇂ / ⇂
|
||
'\u02d9': '˙', # ˙ / ˙ / ˙
|
||
'\u222b': '∫', # ∫ / ∫ / ∫
|
||
'\u22c4': '⋄', # ⋄ / ⋄ / ⋄ / ⋄
|
||
'\u03b5': 'ε', # ε / ε / ε
|
||
'\u03dd': 'ϝ', # ϝ / ϝ / ϝ
|
||
'\u22c7': '⋇', # ⋇ / ⋇ / ⋇
|
||
'\u231e': '⌞', # ⌞ / ⌞ / ⌞
|
||
'\u2250': '≐', # ≐ / ≐ / ≐ / ≐
|
||
'\u2251': '≑', # ≑ / ≑ / ≑
|
||
'\u2238': '∸', # ∸ / ∸ / ∸
|
||
'\u2214': '∔', # ∔ / ∔ / ∔
|
||
'\u22a1': '⊡', # ⊡ / ⊡ / ⊡
|
||
'\u21d3': '⇓', # ⇓ / ⇓ / ⇓ / ⇓
|
||
'\u21d0': '⇐', # ⇐ / ⇐ / ⇐ / ⇐
|
||
'\u21d4': '⇔', # ⇔ / ⇔ / ⇔ / ⇔ / ⇔
|
||
'\u27f8': '⟸', # ⟸ / ⟸ / ⟸ / ⟸
|
||
'\u27fa': '⟺', # ⟺ / ⟺ / ⟺ / ⟺
|
||
'\u27f9': '⟹', # ⟹ / ⟹ / ⟹ / ⟹
|
||
'\u21d2': '⇒', # ⇒ / ⇒ / ⇒ / ⇒ / ⇒
|
||
'\u22a8': '⊨', # ⊨ / ⊨ / ⊨
|
||
'\u21d1': '⇑', # ⇑ / ⇑ / ⇑ / ⇑
|
||
'\u2202': '∂', # ∂ / ∂ / ∂
|
||
'\u21d5': '⇕', # ⇕ / ⇕ / ⇕ / ⇕
|
||
'\u2225': '∥', # ∥ / ∥ / ∥ / ∥ / ∥ / ∥
|
||
'\u2193': '↓', # ↓ / ↓ / ↓ / ↓ / ↓
|
||
'\u21f5': '⇵', # ⇵ / ⇵ / ⇵
|
||
'\u21bd': '↽', # ↽ / ↽ /↽ / ↽
|
||
'\u21c1': '⇁', # ⇁ / ⇁ / ⇁ / ⇁
|
||
'\u22a4': '⊤', # ⊤ / ⊤ / ⊤
|
||
'\u21a7': '↧', # ↧ / ↧ / ↧
|
||
'\u2910': '⤐', # ⤐ / ⤐ / ⤐
|
||
'\u231f': '⌟', # ⌟ / ⌟ / ⌟
|
||
'\u25bf': '▿', # ▿ / ▿ / ▿
|
||
'\u296f': '⥯', # ⥯ / ⥯ / ⥯
|
||
'\u2256': '≖', # ≖ / ≖ / ≖
|
||
'\u2255': '≕', # ≕ / ≕ / ≕
|
||
'\u2147': 'ⅇ', # ⅇ / ⅇ / ⅇ / ⅇ
|
||
'\u2252': '≒', # ≒ / ≒ / ≒
|
||
'\u2a96': '⪖', # ⪖ / ⪖ / ⪖
|
||
'\u2208': '∈', # ∈ / ∈ / ∈ / ∈ / ∈
|
||
'\u2a95': '⪕', # ⪕ / ⪕ / ⪕
|
||
'\u2205': '∅', # ∅ / ∅ / ∅ / ∅ / ∅
|
||
'\u03f5': 'ϵ', # ϵ / ϵ / ϵ / ϵ
|
||
'\u2242': '≂', # ≂ / ≂ / ≂ / ≂
|
||
'\u225f': '≟', # ≟ / ≟ / ≟
|
||
'\u21cc': '⇌', # ⇌ / ⇌ / ⇌ / ⇌
|
||
'\u2253': '≓', # ≓ / ≓ / ≓
|
||
'\u2130': 'ℰ', # ℰ / ℰ / ℰ
|
||
'\u22d4': '⋔', # ⋔ / ⋔ / ⋔
|
||
'\u2131': 'ℱ', # ℱ / ℱ / ℱ
|
||
'\u2322': '⌢', # ⌢ / ⌢ / ⌢
|
||
'\u2a86': '⪆', # ⪆ / ⪆ / ⪆
|
||
'\u2267': '≧', # ≧ / ≧ / ≧ / ≧
|
||
'\u2a8c': '⪌', # ⪌ / ⪌ / ⪌
|
||
'\u22db': '⋛', # ⋛ / ⋛ / ⋛ / ⋛
|
||
'\u2265': '≥', # ≥ / ≥ / ≥ / ≥
|
||
'\u2a7e': '⩾', # ⩾ / ⩾ / ⩾ / ⩾
|
||
'\u22d9': '⋙', # ⋙ / ⋙ / ⋙
|
||
'\u226b': '≫', # ≫ / &gg ;/ ≫ / ≫
|
||
'\u2277': '≷', # ≷ / ≷ / ≷ / ≷
|
||
'\u2a8a': '⪊', # ⪊ / ⪊ / ⪊
|
||
'\u2269': '≩', # ≩ / ≩ / ≩
|
||
'\u2260': '≠', # ≠ / ≠ / ≠
|
||
'\u2a88': '⪈', # ⪈ / ⪈ / ⪈
|
||
'\u2273': '≳', # ≳ / ≳ / ≳ / ≳
|
||
'\u22d7': '⋗', # ⋗ / ⋗ / ⋗
|
||
'\u200a': ' ', # /   /  
|
||
'\u210b': 'ℋ', # ℋ / ℋ / ℋ / ℋ
|
||
'\u21ad': '↭', # ↭ / ↭ / ↭
|
||
'\u210f': 'ℏ', # ℏ / ℏ / ℏ / ℏ / ℏ
|
||
'\u210c': 'ℌ', # ℌ / ℌ / ℌ
|
||
'\u2925': '⤥', # ⤥ / ⤥ / ⤥
|
||
'\u2926': '⤦', # ⤦ / ⤦ / ⤦
|
||
'\u21a9': '↩', # ↩ / ↩ / ↩
|
||
'\u21aa': '↪', # ↪ / ↪ / ↪
|
||
'\u210d': 'ℍ', # ℍ / ℍ / ℍ
|
||
'\u2063': '⁣', # / ⁣ / ⁣
|
||
'\u2111': 'ℑ', # ℑ / ℑ / ℑ / ℑ / ℑ
|
||
'\u2148': 'ⅈ', # ⅈ / ⅈ / ⅈ
|
||
'\u2a0c': '⨌', # ⨌ / ⨌ / ⨌
|
||
'\u222d': '∭', # ∭ / ∭ / ∭
|
||
'\u2110': 'ℐ', # ℐ / ℐ / ℐ
|
||
'\u0131': 'ı', # ı / ı / ı
|
||
'\u22ba': '⊺', # ⊺ / ⊺ / ⊺
|
||
'\u2124': 'ℤ', # ℤ / ℤ / ℤ
|
||
'\u2a3c': '⨼', # ⨼ / ⨼ / ⨼
|
||
'\u2062': '⁢', # / ⁢ / ⁢
|
||
'\u03f0': 'ϰ', # ϰ / ϰ / ϰ
|
||
'\u21da': '⇚', # ⇚ / ⇚ / ⇚
|
||
'\u2112': 'ℒ', # ℒ / ℒ / ℒ / ℒ
|
||
'\u27e8': '⟨', # ⟨ / ⟨ / ⟨ / ⟨
|
||
'\u2a85': '⪅', # ⪅ / ⪅ / ⪅
|
||
'\u219e': '↞', # ↞ / ↞ / ↞
|
||
'\u21e4': '⇤', # ⇤ / ⇤ / ⇤
|
||
'\u21ab': '↫', # ↫ / ↫ / ↫
|
||
'\u21a2': '↢', # ↢ / ↢ / ↢
|
||
'\u2266': '≦', # ≦ / ≦ / ≦ / ≦
|
||
'\u2190': '←', # ← / ← / ← / ← / ← / ←
|
||
'\u21c6': '⇆', # ⇆ / ⇆ / ⇆ / ⇆
|
||
'\u27e6': '⟦', # ⟦ / ⟦ / ⟦
|
||
'\u21bc': '↼', # ↼ / ↼ / ↼ / ↼
|
||
'\u21c7': '⇇', # ⇇ / ⇇ / ⇇
|
||
'\u2194': '↔', # ↔ / ↔ / ↔ / ↔
|
||
'\u21cb': '⇋', # ⇋ / ⇋ / ⇋ / ⇋
|
||
'\u21a4': '↤', # ↤ / ↤ / ↤
|
||
'\u22cb': '⋋', # ⋋ / ⋋ / ⋋
|
||
'\u22b2': '⊲', # ⊲ / ⊲ / ⊲ / ⊲
|
||
'\u22b4': '⊴', # ⊴ / ⊴ / ⊴ / ⊴
|
||
'\u21bf': '↿', # ↿ / ↿ / ↿ / ↿
|
||
'\u2308': '⌈', # ⌈ / ⌈ / ⌈
|
||
'\u230a': '⌊', # ⌊ / ⌊ / ⌊
|
||
'\u2a8b': '⪋', # ⪋ / ⪋ / ⪋
|
||
'\u22da': '⋚', # ⋚ / ⋚ / ⋚ / ⋚
|
||
'\u2a7d': '⩽', # ⩽ / ⩽ / ⩽ / ⩽
|
||
'\u22d6': '⋖', # ⋖ / ⋖ / ⋖
|
||
'\u2276': '≶', # ≶ / ≶ / ≶ / ≶
|
||
'\u2272': '≲', # ≲ / ≲ / ≲ / ≲
|
||
'\u226a': '≪', # ≪ / ≪ / ≪ / ≪
|
||
'\u23b0': '⎰', # ⎰ / ⎰ / ⎰
|
||
'\u2a89': '⪉', # ⪉ / ⪉ / ⪉
|
||
'\u2268': '≨', # ≨ / ≨ / ≨
|
||
'\u2a87': '⪇', # ⪇ / ⪇ / ⪇
|
||
'\u27f5': '⟵', # ⟵ / ⟵ / ⟵ / ⟵
|
||
'\u27f7': '⟷', # ⟷ / ⟷ / ⟷ / ⟷
|
||
'\u27fc': '⟼', # ⟼ / ⟼ / ⟼
|
||
'\u27f6': '⟶', # ⟶ / ⟶ / ⟶ / ⟶
|
||
'\u21ac': '↬', # ↬ / ↬ / ↬
|
||
'\u201e': '„', # „ / „ / „
|
||
'\u2199': '↙', # ↙ / ↙ / ↙ / ↙
|
||
'\u2198': '↘', # ↘ / ↘ / ↘ / ↘
|
||
'\u21b0': '↰', # ↰ / ↰ / ↰
|
||
'\u25c3': '◃', # ◃ / ◃ / ◃
|
||
'\u2720': '✠', # ✠ / ✠ / ✠
|
||
'\u21a6': '↦', # ↦ / ↦ / ↦ / ↦
|
||
'\u21a5': '↥', # ↥ / ↥ / ↥
|
||
'\u2133': 'ℳ', # ℳ / ℳ / ℳ / ℳ
|
||
'\u2223': '∣', # ∣ / ∣ / ∣ / ∣ / ∣
|
||
'\u2213': '∓', # ∓ / ∓ / ∓ / ∓
|
||
'\u2026': '…', # … / … / …
|
||
'\u22b8': '⊸', # ⊸ / ⊸ / ⊸
|
||
'\u2249': '≉', # ≉ / ≉ / ≉ / ≉
|
||
'\u266e': '♮', # ♮ / ♮ / ♮
|
||
'\u2115': 'ℕ', # ℕ / ℕ / ℕ
|
||
'\u2247': '≇', # ≇ / ≇ / ≇
|
||
'\u2197': '↗', # ↗ / ↗ / ↗ / ↗
|
||
'\u200b': '​', # / ​ / ​ / ​
|
||
# ​ / ​
|
||
'\u2262': '≢', # ≢ / ≢ / ≢
|
||
'\u2928': '⤨', # ⤨ / ⤨ / ⤨
|
||
'\u2203': '∃', # ∃ / ∃ / ∃
|
||
'\u2204': '∄', # ∄ / ∄ / ∄ / ∄
|
||
'\u2271': '≱', # ≱ / ≱ / ≱ / ≱
|
||
'\u2275': '≵', # ≵ / ≵ / ≵
|
||
'\u226f': '≯', # ≯ / ≯ / ≯ / ≯
|
||
'\u21ce': '⇎', # ⇎ / ⇎ / ⇎
|
||
'\u21ae': '↮', # ↮ / ↮ / ↮
|
||
'\u220b': '∋', # ∋ / ∋ / ∋ / ∋ / ∋
|
||
'\u21cd': '⇍', # ⇍ / ⇍ / ⇍
|
||
'\u219a': '↚', # ↚ / ↚ / ↚
|
||
'\u2270': '≰', # ≰ / ≰ / ≰ / ≰
|
||
'\u226e': '≮', # ≮ / ≮ / ≮ / ≮
|
||
'\u2274': '≴', # ≴ / ≴ / ≴
|
||
'\u22ea': '⋪', # ⋪ / ⋪ / ⋪ / ⋪
|
||
'\u22ec': '⋬', # ⋬ / ⋬ / ⋬ / ⋬
|
||
'\u2224': '∤', # ∤ / ∤ / ∤ / ∤ / ∤
|
||
'\u2226': '∦', # ∦ / ∦ / ∦ / ∦ / ∦ / ∦
|
||
'\u2209': '∉', # ∉ / ∉ / ∉ / ∉
|
||
'\u2279': '≹', # ≹ / ≹ / ≹
|
||
'\u2278': '≸', # ≸ / ≸ / ≸
|
||
'\u220c': '∌', # ∌ / ∌ / ∌ / ∌
|
||
'\u2280': '⊀', # ⊀ / ⊀ / ⊀ / ⊀
|
||
'\u22e0': '⋠', # ⋠ / ⋠ / ⋠
|
||
'\u22eb': '⋫', # ⋫ / ⋫ / ⋫ / ⋫
|
||
'\u22ed': '⋭', # ⋭ / ⋭ / ⋭ / ⋭
|
||
'\u22e2': '⋢', # ⋢ / ⋢ / ⋢
|
||
'\u22e3': '⋣', # ⋣ / ⋣ / ⋣
|
||
'\u2288': '⊈', # ⊈ / ⊈ / ⊈ / ⊈
|
||
'\u2281': '⊁', # ⊁ / ⊁ / ⊁ / ⊁
|
||
'\u22e1': '⋡', # ⋡ / ⋡ / ⋡
|
||
'\u2289': '⊉', # ⊉ / ⊉ / ⊉ / ⊉
|
||
'\u2241': '≁', # ≁ / ≁ / ≁
|
||
'\u2244': '≄', # ≄ / ≄ / ≄ / ≄
|
||
'\u21cf': '⇏', # ⇏ / ⇏ / ⇏
|
||
'\u219b': '↛', # ↛ / ↛ / ↛
|
||
'\u2196': '↖', # ↖ / ↖ / ↖ / ↖
|
||
'\u2134': 'ℴ', # ℴ / ℴ / ℴ / ℴ
|
||
'\u203e': '‾', # ̄ / ‾ / ‾
|
||
'\u23b4': '⎴', # ⎴ / ⎴ / ⎴
|
||
'\u03d6': 'ϖ', # ϖ / ϖ / ϖ
|
||
'\u03d5': 'ϕ', # ϕ / ϕ / ϕ / ϕ
|
||
'\u2665': '♥', # ♥ / ♥ / ♥ /
|
||
'\u2119': 'ℙ', # ℙ / ℙ / ℙ
|
||
'\u227a': '≺', # ≺ / ≺ / ≺ / ≺
|
||
'\u2ab7': '⪷', # ⪷ / ⪷ / ⪷
|
||
'\u227c': '≼', # ≼ / ≼ / ≼ / ≼
|
||
'\u2aaf': '⪯', # ⪯ / ⪯ / ⪯ / ⪯
|
||
'\u227e': '≾', # ≾ / ≾ / ≾ / ≾
|
||
'\u2ab9': '⪹', # ⪹ / ⪹ / ⪹
|
||
'\u2ab5': '⪵', # ⪵ / ⪵ / ⪵
|
||
'\u22e8': '⋨', # ⋨ / ⋨ / ⋨
|
||
'\u220f': '∏', # ∏ / ∏ / ∏
|
||
'\u221d': '∝', # ∝ / ∝ / ∝ / ∝ / ∝ / ∝
|
||
'\u211a': 'ℚ', # ℚ / ℚ / ℚ
|
||
'\u21db': '⇛', # ⇛ / ⇛ / ⇛
|
||
'\u27e9': '⟩', # ⟩ / ⟩ / ⟩ / ⟩
|
||
'\u21a0': '↠', # ↠ / ↠ / ↠
|
||
'\u21e5': '⇥', # ⇥ / ⇥ / ⇥
|
||
'\u21a3': '↣', # ↣ / ↣ / ↣
|
||
'\u2309': '⌉', # ⌉ / ⌉ / ⌉
|
||
'\u219d': '↝', # ↝ / ↝ / ↝
|
||
'\u03a9': 'Ω', # Ω / Ω / Ω
|
||
'\u211c': 'ℜ', # ℜ / ℜ / ℜ / ℜ / ℜ
|
||
'\u211b': 'ℛ', # ℛ / ℛ / ℛ
|
||
'\u211d': 'ℝ', # ℝ / ℝ / ℝ
|
||
'\u21c0': '⇀', # ⇀ / ⇀ / ⇀ / ⇀
|
||
'\u03f1': 'ϱ', # ϱ / ϱ / ϱ
|
||
'\u2192': '→', # → / → / → / → / → / →
|
||
'\u21c4': '⇄', # ⇄ / ⇄ / ⇄ / ⇄
|
||
'\u27e7': '⟧', # ⟧ / ⟧ / ⟧
|
||
'\u230b': '⌋', # ⌋ / ⌋ / ⌋
|
||
'\u21c9': '⇉', # ⇉ / ⇉ / ⇉
|
||
'\u22a2': '⊢', # ⊢ / ⊢ / ⊢
|
||
'\u22cc': '⋌', # ⋌ / ⋌ / ⋌
|
||
'\u22b3': '⊳', # ⊳ / ⊳ / ⊳ / ⊳
|
||
'\u22b5': '⊵', # ⊵ / ⊵ / ⊵ / ⊵
|
||
'\u21be': '↾', # ↾ / ↾ / ↾ / ↾
|
||
'\u23b1': '⎱', # ⎱ / ⎱ / ⎱
|
||
'\u201c': '“', # “ / “ / “
|
||
'\u2018': '‘', # ‘ / ‘ / ‘
|
||
'\u21b1': '↱', # ↱ / ↱ / ↱
|
||
'\u25b9': '▹', # ▹ / ▹ / ▹
|
||
'\u227b': '≻', # ≻ / ≻ / ≻ / ≻
|
||
'\u2ab8': '⪸', # ⪸ / ⪸ / ⪸
|
||
'\u227d': '≽', # ≽ / ≽ / ≽ / ≽
|
||
'\u2ab0': '⪰', # ⪰ / ⪰ / ⪰ / ⪰
|
||
'\u2aba': '⪺', # ⪺ / ⪺ / ⪺
|
||
'\u2ab6': '⪶', # ⪶ / ⪶ / ⪶
|
||
'\u22e9': '⋩', # ⋩ / ⋩ / ⋩
|
||
'\u227f': '≿', # ≿ / ≿ / ≿ / ≿
|
||
'\u2929': '⤩', # ⤩ / ⤩ / ⤩
|
||
'\u03c2': 'ς', # ς / ς / ς / ς
|
||
'\u2243': '≃', # ≃ / ≃ / ≃ / ≃
|
||
'\u2323': '⌣', # ⌣ / ⌣ / ⌣
|
||
'\u2660': '♠', # ♠ / ♠ / ♠ /
|
||
'\u2293': '⊓', # ⊓ / ⊓ / ⊓
|
||
'\u2294': '⊔', # ⊔ / ⊔ / ⊔
|
||
'\u221a': '√', # √ / √ / √
|
||
'\u228f': '⊏', # ⊏ / ⊏ / ⊏ / ⊏
|
||
'\u2291': '⊑', # ⊑ / ⊑ / ⊑ / ⊑
|
||
'\u2290': '⊐', # ⊐ / ⊐ / ⊐ / ⊐
|
||
'\u2292': '⊒', # ⊒ / ⊒ / ⊒ / ⊒
|
||
'\u25a1': '□', # □ / □ / □ / □
|
||
'\u22c6': '⋆', # ⋆ / ⋆ / ⋆
|
||
'\u22d0': '⋐', # ⋐ / ⋐ / ⋐
|
||
'\u2282': '⊂', # ⊂ / ⊂ / ⊂
|
||
'\u2ac5': '⫅', # ⫅ / ⫅ / ⫅
|
||
'\u2acb': '⫋', # ⫋ / ⫋ / ⫋
|
||
'\u228a': '⊊', # ⊊ / ⊊ / ⊊
|
||
'\u2286': '⊆', # ⊆ / ⊆ / ⊆ / ⊆
|
||
'\u2211': '∑', # ∑ / ∑ / ∑
|
||
'\u22d1': '⋑', # ⋑ / ⋑ / ⋑
|
||
'\u2ac6': '⫆', # ⫆ / ⫆ / ⫆
|
||
'\u2283': '⊃', # ⊃ / ⊃ / ⊃ / ⊃
|
||
'\u2287': '⊇', # ⊇ / ⊇ / ⊇ / ⊇
|
||
'\u2acc': '⫌', # ⫌ / ⫌ / ⫌
|
||
'\u228b': '⊋', # ⊋ / ⊋ / ⊋
|
||
'\u223c': '∼', # ∼ / ∼ / ∼ / ∼ / ∼
|
||
'\u2245': '≅', # ≅ / ≅ / ≅
|
||
'\u20db': '⃛', # ⃛ / ⃛ / ⃛
|
||
'\u2234': '∴', # ∴ / ∴ / ∴ / ∴
|
||
'\u03d1': 'ϑ', # ϑ / ϑ / ϑ / ϑ
|
||
'\u2122': '™', # ™ / ™ / ™
|
||
'\u25b5': '▵', # ▵ / ▵ / ▵
|
||
'\u225c': '≜', # ≜ / ≜ / ≜
|
||
'\u21c5': '⇅', # ⇅ / ⇅ / ⇅
|
||
'\u296e': '⥮', # ⥮ / ⥮ / ⥮
|
||
'\u231c': '⌜', # ⌜ / ⌜ / ⌜
|
||
'\u03d2': 'ϒ', # ϒ / ϒ / ϒ
|
||
'\u03c5': 'υ', # υ / υ / υ
|
||
'\u228e': '⊎', # ⊎ / ⊎ / ⊎
|
||
'\u2195': '↕', # ↕ / ↕ / ↕ / ↕
|
||
'\u2191': '↑', # ↑ / ↑ / ↑ / ↑ / ↑
|
||
'\u21c8': '⇈', # ⇈ / ⇈ / ⇈
|
||
'\u231d': '⌝', # ⌝ / ⌝ / ⌝
|
||
'\u2016': '‖', # ‖ / ‖ / ‖
|
||
'\u2228': '∨', # ∨ / ∨ / ∨
|
||
'\u2009': ' ', # /   /  
|
||
'\u2240': '≀', # ≀ / ≀ / ≀ / ≀
|
||
'\u2128': 'ℨ', # ℨ / ℨ / ℨ
|
||
'\u2118': '℘', # ℘ / ℘ / ℘
|
||
}
|
||
|
||
# === Динамическая генерация карт преобразования ===
|
||
|
||
def _build_translation_maps() -> dict[str, str]:
|
||
"""
|
||
Создает карту для кодирования на лету, используя все доступные источники
|
||
из html.entities и строгий порядок приоритетов для обеспечения
|
||
предсказуемого и детерминированного результата.
|
||
"""
|
||
# ШАГ 1: Создаем ЕДИНУЮ и ПОЛНУЮ карту {каноническое_имя: числовой_код}.
|
||
# Это решает проблему разных форматов и дубликатов с точкой с запятой.
|
||
unified_name2codepoint = {}
|
||
|
||
# Сначала обрабатываем большой исторический словарь.
|
||
for name, codepoint in entities.name2codepoint.items():
|
||
# Нормализуем имя СРАЗУ, убирая опциональную точку с запятой (в html.entities предусмотрено, что иногда
|
||
# символ `;` не ставится всякими неаккуратными верстальщиками и парсерами).
|
||
canonical_name = name.rstrip(';')
|
||
unified_name2codepoint[canonical_name] = codepoint
|
||
# Затем обновляем его современным стандартом html5.
|
||
# Это гарантирует, что если мнемоника есть в обоих, будет использована версия из html5.
|
||
for name, char in entities.html5.items():
|
||
# НОВОЕ: Проверяем, что значение является ОДИНОЧНЫМ символом.
|
||
# Наш кодек, основанный на str.translate, не может обрабатывать
|
||
# мнемоники, которые соответствуют строкам из нескольких символов
|
||
# (например, символ + вариативный селектор). Мы их игнорируем.
|
||
if len(char) != 1:
|
||
continue
|
||
# Нормализуем имя СРАЗУ.
|
||
canonical_name = name.rstrip(';')
|
||
unified_name2codepoint[canonical_name] = ord(char)
|
||
|
||
# Теперь у нас есть полный и консистентный словарь unified_name2codepoint.
|
||
# На его основе строим нашу карту для кодирования.
|
||
encode_map = {}
|
||
|
||
# ШАГ 2: Высший приоритет. Загружаем наши кастомные правила.
|
||
encode_map.update(CUSTOM_ENCODE_MAP)
|
||
|
||
# ШАГ 3: Следующий приоритет. Добавляем числовое кодирование.
|
||
for char in ALWAYS_ENCODE_TO_NUMERIC_CHARS:
|
||
if char not in encode_map:
|
||
encode_map[char] = f'&#{ord(char)};'
|
||
|
||
# ШАГ 4: Низший приоритет. Заполняем все остальное из нашей
|
||
# объединенной и нормализованной карты unified_name2codepoint.
|
||
for name, codepoint in unified_name2codepoint.items():
|
||
char = chr(codepoint)
|
||
if char not in encode_map and char not in NEVER_ENCODE_CHARS:
|
||
# Теперь 'name' - это уже каноническое имя без ';',
|
||
# поэтому дополнительная нормализация не нужна. Код стал проще!
|
||
encode_map[char] = f'&{name};'
|
||
|
||
return encode_map
|
||
|
||
|
||
# Создаем карту один раз при импорте модуля.
|
||
ENCODE_MAP = _build_translation_maps()
|
||
|
||
# --- Публичный API модуля ---
|
||
def get_encode_map():
|
||
"""Возвращает готовую карту для кодирования."""
|
||
return ENCODE_MAP |