529 lines
32 KiB
Python
529 lines
32 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])
|
||
|
||
|
||
# === ИСТОЧНИК ПРАВДЫ ===
|
||
# --- Базовые алфавиты: Эти константы используются как для правил переноса, так и для правил кодирования ---
|
||
|
||
# Русский алфавит
|
||
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
|
||
|
||
# === КОНСТАНТЫ ДЛЯ КОДИРОВАНИЯ HTML-МНЕМНОИКОВ ===
|
||
# --- ЧЕРНЫЙ СПИСОК: Символы, которые НИКОГДА не нужно кодировать в мнемоники ---
|
||
NEVER_ENCODE_CHARS = (frozenset(['!', '#', '%', '(', ')', '*', ',', '.', '/', ':', ';', '=', '?', '@',
|
||
'[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', '\n', '\t', '\r'])
|
||
| RU_ALPHABET_FULL | EN_ALPHABET_FULL)
|
||
|
||
# 2. БЕЛЫЙ СПИСОК (ДЛЯ БЕЗОПАСНОСТИ):
|
||
# Символы, которые ВСЕГДА должны превращаться в мнемоники в "безопасных" режимах вывода. Сюда добавлены символы,
|
||
# которые не видны, на глаз и не отличимы друг от друга в обычном тексте, или очень специфичные
|
||
SAFE_MODE_CHARS_TO_MNEMONIC = frozenset([
|
||
'<', '>', '&', '"', '\'',
|
||
'\u00AD', # Мягкий перенос (Soft Hyphen) -- ­
|
||
'\u00A0', # Неразрывный пробел (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': '&', # & / & / &
|
||
'\u0026': '&', # & / & / &
|
||
'\u003e': '>', # > / > / >
|
||
'\u00ae': '®', # ® / ® / ® / ®
|
||
'\u00b7': '·', # · / · / · / ·
|
||
'\u0060': '`', # ` / grave / DiacriticalGrave
|
||
'\u00a8': '¨', # ¨ / ¨ / ¨ / ¨
|
||
'\u00b1': '±', # ± / pm / PlusMinus
|
||
'\u00bd': '½', # ½ / ½ / ½
|
||
'\u223e': '∾', # ∾ / ∾ / ∾
|
||
'\u2207': '∇', # ∇ / ∇ / ∇
|
||
'\u2061': '⁡', # / ⁡ / ⁡
|
||
'\u2221': '∡', # ∡ / ∡ / ∡
|
||
'\u2248': '≈', # ≈ / ≈ / ≈ / ≈ / ≈ / ≈
|
||
'\u224a': '≊', # ≊ / ≊ / ≊
|
||
'\u2254': '≔', # ≔ / ≔ / ≔ / ≔
|
||
'\u224d': '≍', # ≍ / ≍ / ≍
|
||
'\u2233': '∳', # ∳ / awconint / CounterClockwiseContourIntegral
|
||
'\u224c': '≌', # ≌ / bcong / backcong
|
||
'\u03f6': '϶', # ϶ / bepsi / backepsilon
|
||
'\u2035': '‵', # ‵ / bprime / backprime
|
||
'\u223d': '∽', # ∽ / bsim / backsim
|
||
'\u22cd': '⋍', # ⋍ / bsime / backsimeq
|
||
'\u2216': '∖', # ∖ / ∖ / ∖ / ∖ / ∖ / ∖
|
||
'\u2306': '⌆', # ⌆ / Barwed / doublebarwedge
|
||
'\u2305': '⌅', # ⌅ / barwed / barwedge
|
||
'\u23b5': '⎵', # ⎵ / bbrk / UnderBracket
|
||
'\u2235': '∵', # ∵ / becaus / because / Because
|
||
'\u212c': 'ℬ', # ℬ / Bscr / bernou / Bernoullis
|
||
'\u226c': '≬', # ≬ / ≬ / ≬
|
||
'\u22c2': '⋂', # ⋂ / ⋂ / ⋂ / ⋂
|
||
'\u25ef': '◯', # ◯ / ◯ / ◯
|
||
'\u22c3': '⋃', # ⋃ / ⋃ / ⋃ / ⋃
|
||
'\u2a00': '⨀', # ⨀ / ⨀ / ⨀
|
||
'\u2a01': '⨁', # ⨁ / ⨁ / ⨁
|
||
'\u2a02': '⨂', # ⨂ / ⨂ / ⨂
|
||
'\u2a06': '⨆', # ⨆ / ⨆ / ⨆
|
||
'\u2605': '★', # ★ / ★ / ★
|
||
'\u25bd': '▽', # ▽ / ▽ / ▽
|
||
'\u25b3': '△', # △ / △ / △
|
||
'\u2a04': '⨄', # ⨄ / ⨄ / ⨄
|
||
'\u22c1': '⋁', # ⋁ / ⋁ / ⋁ / ⋁
|
||
'\u22c0': '⋀', # ⋀ / Wedge / ⋀ / $bigwedge;
|
||
'\u290d': '⤍', # ⤍ / rbarr / bkarow
|
||
'\u29eb': '⧫', # ⧫ / ⧫ / ⧫
|
||
'\u25aa': '▪', # ▪ / ▪ / ▪ / ▪ / ▪
|
||
'\u25b4': '▴', # ▴ / ▴ / ▴
|
||
'\u25be': '▾', # ▾ / ▾ / ▾
|
||
'\u25c2': '◂', # ◂ / ◂ / ◂
|
||
'\u25b8': '▸', # ▸ / ▸ / ▸
|
||
'\u22a5': '⊥', # ⊥ / ⊥ / ⊥ / ⊥ / ⊥
|
||
'\u2500': '─', # ─ / ─ / ─
|
||
'\u229f': '⊟', # ⊟ / ⊟ / ⊟
|
||
'\u229e': '⊞', # ⊞ / ⊞ / ⊞
|
||
'\u22a0': '⊠', # ⊠ / ⊠ / ⊠
|
||
'\u02d8': '˘', # ˘ / breve / Breve
|
||
'\u224e': '≎', # ≎ / ≎ / ≎ / ≎
|
||
'\u224f': '≏', # ≏ / ≏ / ≏ / ≏
|
||
'\u2145': 'ⅅ', # ⅅ / ⅅ / ⅅ
|
||
'\u02c7': 'ˇ', # ˇ / ˇ / ˇ
|
||
'\u212d': 'ℭ', # ℭ / Cfr / Cayleys
|
||
'\u2713': '✓', # ✓ / check / checkmark
|
||
'\u2257': '≗', # ≗ / cire / circeq
|
||
'\u21ba': '↺', # ↺ / olarr / circlearrowleft
|
||
'\u21bb': '↻', # ↻ / orarr / circlearrowright
|
||
'\u229b': '⊛', # ⊛ / ⊛ / ⊛
|
||
'\u229a': '⊚', # ⊚ / ⊚ / ⊚
|
||
'\u229d': '⊝', # ⊝ / ⊝ / ⊝
|
||
'\u2299': '⊙', # ⊙ / odot / CircleDot
|
||
'\u2200': '∀', # ∀ / ∀ / ∀
|
||
'\u24c8': 'Ⓢ', # Ⓢ / Ⓢ / Ⓢ
|
||
'\u2296': '⊖', # ⊖ / ⊖ / ⊖
|
||
'\u2232': '∲', # ∲ / cwconint / ClockwiseContourIntegral
|
||
'\u201d': '”', # ” / ” / rdquor / CloseCurlyDoubleQuote
|
||
'\u2019': '’', # ’ / ’ / rsquor / CloseCurlyQuote
|
||
'\u2237': '∷', # ∷ / Colon / Proportion
|
||
'\u2201': '∁', # ∁ / comp / complement
|
||
'\u2218': '∘', # ∘ / compfn / SmallCircle
|
||
'\u2102': 'ℂ', # ℂ / Copf / complexes
|
||
'\u222f': '∯', # ∯ / Conint / DoubleContourIntegral
|
||
'\u222e': '∮', # ∮ / oint / conint / ContourIntegral
|
||
'\u2210': '∐', # ∐ / coprod / Coproduct
|
||
'\u22de': '⋞', # ⋞ / cuepr / curlyeqprec
|
||
'\u22df': '⋟', # ⋟ / cuesc / curlyeqsucc
|
||
'\u21b6': '↶', # ↶ / cularr / curvearrowleft
|
||
'\u21b7': '↷', # ↷ / curarr / curvearrowright
|
||
'\u22ce': '⋎', # ⋎ / cuvee / curlyvee
|
||
'\u22cf': '⋏', # ⋏ / cuwed / curlywedge
|
||
'\u2010': '‐', # ‐ / ‐ / ‐
|
||
'\u2ae4': '⫤', # ⫤ / Dashv / DoubleLeftTee
|
||
'\u22a3': '⊣', # ⊣ / dashv / LeftTee
|
||
'\u290f': '⤏', # ⤏ / ⤏ / ⤏
|
||
'\u02dd': '˝', # ˝ / dblac / DiacriticalDoubleAcute
|
||
'\u2146': 'ⅆ', # ⅆ / dd / DifferentialD
|
||
'\u21ca': '⇊', # ⇊ / ddarr / downdownarrows
|
||
'\u2a77': '⩷', # ⩷ / eDDot / ddotseq
|
||
'\u21c3': '⇃', # ⇃ / ⇃ / ⇃ / ⇃
|
||
'\u21c2': '⇂', # ⇂ / dharr / RightDownVector / downharpoonright
|
||
'\u02d9': '˙', # ˙ / dot / DiacriticalDot
|
||
'\u222b': '∫', # ∫ / ∫ / ∫
|
||
'\u22c4': '⋄', # ⋄ / diam / diamond / Diamond
|
||
'\u03b5': 'ε', # ε / ε / ε
|
||
'\u03dd': 'ϝ', # ϝ / gammad / digamma
|
||
'\u22c7': '⋇', # ⋇ / divonx / divideontimes
|
||
'\u231e': '⌞', # ⌞ / dlcorn / llcorner
|
||
'\u2250': '≐', # ≐ / esdot / doteq / DotEqual
|
||
'\u2251': '≑', # ≑ / eDot / doteqdot
|
||
'\u2238': '∸', # ∸ / minusd / dotminus
|
||
'\u2214': '∔', # ∔ / plusdo / dotplus
|
||
'\u22a1': '⊡', # ⊡ / sdotb / dotsquare
|
||
'\u21d3': '⇓', # ⇓ / ⇓ / ⇓ / ⇓
|
||
'\u21d0': '⇐', # ⇐ / ⇐ / ⇐ / ⇐
|
||
'\u21d4': '⇔', # ⇔ / ⇔ / ⇔ / ⇔ / ⇔
|
||
'\u27f8': '⟸', # ⟸ / xlArr / Longleftarrow / DoubleLongLeftArrow
|
||
'\u27fa': '⟺', # ⟺ / xhArr / Longleftrightarrow / DoubleLongLeftRightArrow
|
||
'\u27f9': '⟹', # ⟹ / xrArr / Longrightarrow / DoubleLongRightArrow
|
||
'\u21d2': '⇒', # ⇒ / ⇒ / ⇒ / ⇒ / ⇒
|
||
'\u22a8': '⊨', # ⊨ / vDash / DoubleRightTee
|
||
'\u21d1': '⇑', # ⇑ / ⇑ / ⇑ / ⇑
|
||
'\u21d5': '⇕', # ⇕ / vArr / Updownarrow / DoubleUpDownArrow
|
||
'\u2225': '∥', # ∥ / par / spar / parallel / shortparallel / DoubleVerticalBar
|
||
'\u2191': '↑', # ↑ / ↑ / ↑ / ↑
|
||
'\u2193': '↓', # ↓ / ↓ / ↓ / ↓ / ↓
|
||
'\u21f5': '⇵', # ⇵ / ⇵ / ⇵
|
||
'\u21bd': '↽', # ↽ / ↽ /↽ / ↽
|
||
'\u21c1': '⇁', # ⇁ / ⇁ / ⇁ / ⇁
|
||
'\u22a4': '⊤', # ⊤ / ⊤ / ⊤
|
||
'\u21a7': '↧', # ↧ / ↧ / ↧
|
||
'\u2910': '⤐', # ⤐ / ⤐ / ⤐
|
||
'\u231f': '⌟', # ⌟ / ⌟ / ⌟
|
||
'\u25bf': '▿', # ▿ / ▿ / ▿
|
||
'\u296f': '⥯', # ⥯ / duhar / ReverseUpEquilibrium
|
||
'\u2256': '≖', # ≖ / ≖ / ≖
|
||
'\u2255': '≕', # ≕ / ecolon / eqcolon
|
||
'\u2147': 'ⅇ', # ⅇ / ⅇ / ⅇ / ⅇ
|
||
'\u2252': '≒', # ≒ / ≒ / ≒
|
||
'\u2a96': '⪖', # ⪖ / ⪖ / ⪖
|
||
'\u2208': '∈', # ∈ / ∈ / ∈ / ∈ / ∈
|
||
'\u2a95': '⪕', # ⪕ / ⪕ / ⪕
|
||
'\u2205': '∅', # ∅ / ∅ / ∅ / ∅ / ∅
|
||
'\u03f5': 'ϵ', # ϵ / epsiv / varepsilon / straightepsilon
|
||
'\u2242': '≂', # ≂ / ≂ / ≂ / ≂
|
||
'\u225f': '≟', # ≟ / equest / questeq
|
||
'\u21cc': '⇌', # ⇌ / ⇌ / ⇌ / ⇌
|
||
'\u2253': '≓', # ≓ / erDot / risingdotseq
|
||
'\u2130': 'ℰ', # ℰ / ℰ / ℰ
|
||
'\u22d4': '⋔', # ⋔ / fork / pitchfork
|
||
'\u2131': 'ℱ', # ℱ / ℱ / ℱ
|
||
'\u2322': '⌢', # ⌢ / frown / sfrown
|
||
'\u2a86': '⪆', # ⪆ / ⪆ / ⪆
|
||
'\u2267': '≧', # ≧ / ≧ / ≧ / ≧
|
||
'\u2a8c': '⪌', # ⪌ / ⪌ / ⪌
|
||
'\u22db': '⋛', # ⋛ / ⋛ / ⋛ / ⋛
|
||
'\u2265': '≥', # ≥ / ≥ / ≥ / ≥
|
||
'\u2a7e': '⩾', # ⩾ / ⩾ / ⩾ / ⩾
|
||
'\u22d9': '⋙', # ⋙ / ⋙ / ⋙
|
||
'\u226b': '≫', # ≫ / &gg ;/ ≫ / ≫
|
||
'\u2277': '≷', # ≷ / ≷ / ≷ / ≷
|
||
'\u2a8a': '⪊', # ⪊ / ⪊ / ⪊
|
||
'\u2269': '≩', # ≩ / ≩ / ≩
|
||
'\u2a88': '⪈', # ⪈ / ⪈ / ⪈
|
||
'\u2273': '≳', # ≳ / ≳ / ≳ / ≳
|
||
'\u22d7': '⋗', # ⋗ / ⋗ / ⋗
|
||
'\u200a': ' ', # /   /  
|
||
'\u210b': 'ℋ', # ℋ / ℋ / ℋ / ℋ
|
||
'\u21ad': '↭', # ↭ / harrw / leftrightsquigarrow
|
||
'\u210f': 'ℏ', # ℏ / ℏ / ℏ / ℏ / ℏ
|
||
'\u210c': 'ℌ', # ℌ / Hfr / Poincareplane
|
||
'\u2925': '⤥', # ⤥ / ⤥ / ⤥
|
||
'\u2926': '⤦', # ⤦ / ⤦ / ⤦
|
||
'\u21a9': '↩', # ↩ / ↩ / ↩
|
||
'\u21aa': '↪', # ↪ / ↪ / ↪
|
||
'\u210d': 'ℍ', # ℍ / Hopf / quaternions
|
||
'\u2063': '⁣', # / ⁣ / ⁣
|
||
'\u2111': 'ℑ', # ℑ / ℑ / ℑ / ℑ / ℑ
|
||
'\u2148': 'ⅈ', # ⅈ / ⅈ / ⅈ
|
||
'\u2a0c': '⨌', # ⨌ / ⨌ / ⨌
|
||
'\u222d': '∭', # ∭ / ∭ / ∭
|
||
'\u2110': 'ℐ', # ℐ / ℐ / ℐ
|
||
'\u0131': 'ı', # ı / ı / ı
|
||
'\u22ba': '⊺', # ⊺ / ⊺ / ⊺
|
||
'\u2124': 'ℤ', # ℤ / ℤ / ℤ
|
||
'\u2a3c': '⨼', # ⨼ / ⨼ / ⨼
|
||
'\u2062': '⁢', # / ⁢ / ⁢
|
||
'\u03f0': 'ϰ', # ϰ / kappav / varkappa
|
||
'\u21da': '⇚', # ⇚ / lAarr / Lleftarrow
|
||
'\u2112': 'ℒ', # ℒ / ℒ / ℒ / ℒ
|
||
'\u27e8': '⟨', # ⟨ / ⟨ / ⟨ / ⟨
|
||
'\u2a85': '⪅', # ⪅ / lap / lessapprox
|
||
'\u219e': '↞', # ↞ / Larr / twoheadleftarrow
|
||
'\u21e4': '⇤', # ⇤ / ⇤ / ⇤
|
||
'\u21ab': '↫', # ↫ / larrlp / looparrowleft
|
||
'\u21a2': '↢', # ↢ / ↢ / ↢
|
||
'\u2266': '≦', # ≦ / lE / leqq / LessFullEqual
|
||
'\u2190': '←', # ← / ← / ← / ← / ← / ←
|
||
'\u21c6': '⇆', # ⇆ / ⇆ / ⇆ / ⇆
|
||
'\u27e6': '⟦', # ⟦ / ⟦ / ⟦
|
||
'\u21bc': '↼', # ↼ / ↼ / ↼ / ↼
|
||
'\u21c7': '⇇', # ⇇ / ⇇ / ⇇
|
||
'\u2194': '↔', # ↔ / ↔ / ↔ / ↔
|
||
'\u21cb': '⇋', # ⇋ / lrhar / leftrightharpoons / ReverseEquilibrium
|
||
'\u21a4': '↤', # ↤ / mapstoleft / LeftTeeArrow
|
||
'\u22cb': '⋋', # ⋋ / lthree / leftthreetimes
|
||
'\u22b2': '⊲', # ⊲ / vltri / LeftTriangle / vartriangleleft
|
||
'\u22b4': '⊴', # ⊴ / ltrie / trianglelefteq / LeftTriangleEqual
|
||
'\u21bf': '↿', # ↿ / uharl / LeftUpVector / upharpoonleft
|
||
'\u2308': '⌈', # ⌈ / ⌈ / ⌈
|
||
'\u230a': '⌊', # ⌊ / ⌊ / ⌊
|
||
'\u2a8b': '⪋', # ⪋ / lEg / lesseqqgtr
|
||
'\u22da': '⋚', # ⋚ / leg / lesseqgtr / LessEqualGreater
|
||
'\u2a7d': '⩽', # ⩽ / les / leqslant / LessSlantEqual
|
||
'\u22d6': '⋖', # ⋖ / ltdot / lessdot
|
||
'\u2276': '≶', # ≶ / lg / lessgtr / LessGreater
|
||
'\u2272': '≲', # ≲ / lsim / lesssim / LessTilde
|
||
'\u226a': '≪', # ≪ / ll / Lt / NestedLessLess
|
||
'\u23b0': '⎰', # ⎰ / lmoust / lmoustache
|
||
'\u2a89': '⪉', # ⪉ / lnap / lnapprox
|
||
'\u2268': '≨', # ≨ / lnE / lneqq
|
||
'\u2a87': '⪇', # ⪇ / lne / lneq
|
||
'\u27f5': '⟵', # ⟵ / xlarr / longleftarrow / LongLeftArrow
|
||
'\u27f7': '⟷', # ⟷ / xharr / longleftrightarrow / LongLeftRightArrow
|
||
'\u27fc': '⟼', # ⟼ / xmap / longmapsto
|
||
'\u27f6': '⟶', # ⟶ / xrarr / LongRightArrow / longrightarrow
|
||
'\u21ac': '↬', # ↬ / rarrlp / looparrowright
|
||
'\u201e': '„', # „ / „ / „
|
||
'\u2199': '↙', # ↙ / swarr / swarrow / LowerLeftArrow
|
||
'\u2198': '↘', # ↘ / searr / searrow / LowerRightArrow
|
||
'\u21b0': '↰', # ↰ / Lsh / lsh
|
||
'\u25c3': '◃', # ◃ / ltri / triangleleft
|
||
'\u2720': '✠', # ✠ / malt / maltese
|
||
'\u21a6': '↦', # ↦ / map / mapsto / RightTeeArrow
|
||
'\u21a5': '↥', # ↥ / mapstoup / UpTeeArrow
|
||
'\u2133': 'ℳ', # ℳ / Mscr / phmmat / Mellintrf
|
||
'\u2223': '∣', # ∣ / mid / smid / shortmid / VerticalBar
|
||
'\u2213': '∓', # ∓ / mp / mnplus / MinusPlus
|
||
'\u22b8': '⊸', # ⊸ / mumap / multimap
|
||
'\u2249': '≉', # ≉ / nap / napprox / NotTildeTilde
|
||
'\u266e': '♮', # ♮ / natur / natural
|
||
'\u2115': 'ℕ', # ℕ / Nopf / naturals
|
||
'\u2247': '≇', # ≇ / ncong / NotTildeFullEqual
|
||
'\u2197': '↗', # ↗ / nearr / nearrow / UpperRightArrow
|
||
'\u200b': '​', # / ZeroWidthSpace / NegativeThinSpace / NegativeThickSpace / NegativeMediumSpace / NegativeVeryThinSpace
|
||
'\u2262': '≢', # ≢ / nequiv / NotCongruent
|
||
'\u2928': '⤨', # ⤨ / toea / nesear
|
||
'\u2203': '∃', # ∃ / ∃ / ∃
|
||
'\u2204': '∄', # ∄ / nexist / nexists / NotExists
|
||
'\u2271': '≱', # ≱ / nge / ngeq / NotGreaterEqual
|
||
'\u2275': '≵', # ≵ / ngsim / NotGreaterTilde
|
||
'\u226f': '≯', # ≯ / ngt / ngtr / NotGreater
|
||
'\u21ce': '⇎', # ⇎ / nhArr / nLeftrightarrow
|
||
'\u21ae': '↮', # ↮ / nharr / nleftrightarrow
|
||
'\u220b': '∋', # ∋ / ∋ / ∋ / ∋ / ∋
|
||
'\u21cd': '⇍', # ⇍ / nlArr / nLeftarrow
|
||
'\u219a': '↚', # ↚ / nlarr / nleftarrow
|
||
'\u2270': '≰', # ≰ / nle / nleq / NotLessEqual
|
||
'\u226e': '≮', # ≮ / nlt / nless / NotLess
|
||
'\u2274': '≴', # ≴ / nlsim / NotLessTilde
|
||
'\u22ea': '⋪', # ⋪ / nltri / ntriangleleft / NotLeftTriangle
|
||
'\u22ec': '⋬', # ⋬ / nltrie / ntrianglelefteq / NotLeftTriangleEqual
|
||
'\u2224': '∤', # ∤ / nmid / nsmid / nshortmid / NotVerticalBar
|
||
'\u2226': '∦', # ∦ / npar / nspar / nparallel / nshortparallel / NotDoubleVerticalBar
|
||
'\u2209': '∉', # ∉ / ∉ / ∉ / ∉
|
||
'\u2279': '≹', # ≹ / ntgl / NotGreaterLess
|
||
'\u2278': '≸', # ≸ / ntlg / NotLessGreater
|
||
'\u220c': '∌', # ∌ / notni / notniva / NotReverseElement
|
||
'\u2280': '⊀', # ⊀ / npr / nprec / NotPrecedes
|
||
'\u22e0': '⋠', # ⋠ / nprcue / NotPrecedesSlantEqual
|
||
'\u22eb': '⋫', # ⋫ / nrtri / ntriangleright / NotRightTriangle
|
||
'\u22ed': '⋭', # ⋭ / nrtrie / ntrianglerighteq / NotRightTriangleEqual
|
||
'\u22e2': '⋢', # ⋢ / nsqsube / NotSquareSubsetEqual
|
||
'\u22e3': '⋣', # ⋣ / nsqsupe / NotSquareSupersetEqual
|
||
'\u2288': '⊈', # ⊈ / nsube / nsubseteq / NotSubsetEqual
|
||
'\u2281': '⊁', # ⊁ / nsc / nsucc / NotSucceeds
|
||
'\u22e1': '⋡', # ⋡ / nsccue / NotSucceedsSlantEqual
|
||
'\u2289': '⊉', # ⊉ / nsupe / nsupseteq / NotSupersetEqual
|
||
'\u2241': '≁', # ≁ / nsim / NotTilde
|
||
'\u2244': '≄', # ≄ / nsime / nsimeq / NotTildeEqual
|
||
'\u21cf': '⇏', # ⇏ / nrArr / nRightarrow
|
||
'\u219b': '↛', # ↛ / nrarr / nrightarrow
|
||
'\u2196': '↖', # ↖ / nwarr / nwarrow / UpperLeftArrow
|
||
'\u2134': 'ℴ', # ℴ / oscr / order / orderof
|
||
'\u23b4': '⎴', # ⎴ / tbrk / OverBracket
|
||
'\u03d5': 'ϕ', # ϕ / phiv / varphi / straightphi
|
||
'\u2665': '♥', # ♥ / ♥ / ♥ /
|
||
'\u2119': 'ℙ', # ℙ / Popf / primes
|
||
'\u227a': '≺', # ≺ / pr / prec / Precedes
|
||
'\u2ab7': '⪷', # ⪷ / prap / precapprox
|
||
'\u227c': '≼', # ≼ / prcue / preccurlyeq / PrecedesSlantEqual
|
||
'\u2aaf': '⪯', # ⪯ / pre / preceq / PrecedesEqual
|
||
'\u227e': '≾', # ≾ / prsim / precsim / PrecedesTilde
|
||
'\u2ab9': '⪹', # ⪹ / prnap / precnapprox
|
||
'\u2ab5': '⪵', # ⪵ / prnE / precneqq
|
||
'\u22e8': '⋨', # ⋨ / prnsim / precnsim
|
||
'\u221d': '∝', # ∝ / ∝ / ∝ / ∝ / ∝ / ∝
|
||
'\u211a': 'ℚ', # ℚ / Qopf / rationals
|
||
'\u21db': '⇛', # ⇛ / rAarr / Rrightarrow
|
||
'\u27e9': '⟩', # ⟩ / ⟩ / ⟩ / ⟩
|
||
'\u21a0': '↠', # ↠ / Rarr / twoheadrightarrow
|
||
'\u21e5': '⇥', # ⇥ / rarrb / RightArrowBar
|
||
'\u21a3': '↣', # ↣ / rarrtl / rightarrowtail
|
||
'\u219d': '↝', # ↝ / rarrw / rightsquigarrow
|
||
|
||
'\u211c': 'ℜ', # ℜ / ℜ / ℜ / ℜ / ℜ
|
||
'\u211b': 'ℛ', # ℛ / Rscr / realine
|
||
'\u211d': 'ℝ', # ℝ / Ropf / reals
|
||
'\u21c0': '⇀', # ⇀ / rharu / RightVector / rightharpoonup
|
||
'\u03f1': 'ϱ', # ϱ / rhov / varrho
|
||
'\u2192': '→', # → / → / → / → / → / →
|
||
'\u21c4': '⇄', # ⇄ / rlarr / rightleftarrows / RightArrowLeftArrow
|
||
'\u27e7': '⟧', # ⟧ / robrk / RightDoubleBracket
|
||
'\u21c9': '⇉', # ⇉ / rrarr / rightrightarrows
|
||
'\u22a2': '⊢', # ⊢ / vdash / RightTee
|
||
'\u22cc': '⋌', # ⋌ / rthree / rightthreetimes
|
||
'\u22b3': '⊳', # ⊳ / vrtri / RightTriangle / vartriangleright
|
||
'\u22b5': '⊵', # ⊵ / rtrie / trianglerighteq / RightTriangleEqual
|
||
'\u21be': '↾', # ↾ / uharr / RightUpVector / upharpoonright
|
||
'\u23b1': '⎱', # ⎱ / rmoust / rmoustache
|
||
'\u21b1': '↱', # ↱ / rsh / Rsh
|
||
'\u25b9': '▹', # ▹ / rtri / triangleright
|
||
'\u227b': '≻', # ≻ / sc / succ / Succeeds
|
||
'\u2ab8': '⪸', # ⪸ / scap / succapprox
|
||
'\u227d': '≽', # ≽ / sccue / succcurlyeq / SucceedsSlantEqual
|
||
'\u2ab0': '⪰', # ⪰ / sce / succeq / SucceedsEqual
|
||
'\u2aba': '⪺', # ⪺ / scnap / succnapprox
|
||
'\u2ab6': '⪶', # ⪶ / scnE / succneqq
|
||
'\u22e9': '⋩', # ⋩ / scnsim / succnsim
|
||
'\u227f': '≿', # ≿ / scsim / succsim / SucceedsTilde
|
||
'\u2929': '⤩', # ⤩ / tosa / seswar
|
||
'\u03c2': 'ς', # ς / ς / ς / ς
|
||
'\u2243': '≃', # ≃ / sime / simeq / TildeEqual
|
||
'\u2323': '⌣', # ⌣ / smile / ssmile
|
||
'\u2293': '⊓', # ⊓ / sqcap / SquareIntersection
|
||
'\u2294': '⊔', # ⊔ / sqcup / SquareUnion
|
||
'\u228f': '⊏', # ⊏ / sqsub / sqsubset / SquareSubset
|
||
'\u2291': '⊑', # ⊑ / sqsube / sqsubseteq / SquareSubsetEqual
|
||
'\u2290': '⊐', # ⊐ / sqsup / sqsupset / SquareSuperset
|
||
'\u2292': '⊒', # ⊒ / sqsupe / sqsupseteq / SquareSupersetEqual
|
||
'\u25a1': '□', # □ / squ / Square / square
|
||
'\u22c6': '⋆', # ⋆ / Star / sstarf
|
||
'\u22d0': '⋐', # ⋐ / Sub / Subset
|
||
'\u2ac5': '⫅', # ⫅ / subE / subseteqq
|
||
'\u2acb': '⫋', # ⫋ / subnE / subsetneqq
|
||
'\u228a': '⊊', # ⊊ / subne / subsetneq
|
||
'\u2286': '⊆', # ⊆ / ⊆ / ⊆ / ⊆
|
||
'\u22d1': '⋑', # ⋑ / Sup / Supset
|
||
'\u2ac6': '⫆', # ⫆ / supE / supseteqq
|
||
'\u2283': '⊃', # ⊃ / ⊃ / ⊃ / ⊃
|
||
'\u2287': '⊇', # ⊇ / ⊇ / ⊇ / ⊇
|
||
'\u2acc': '⫌', # ⫌ / supnE / supsetneqq
|
||
'\u228b': '⊋', # ⊋ / supne / supsetneq
|
||
'\u20db': '⃛', # ⃛ / tdot / TripleDot
|
||
'\u2234': '∴', # ∴ / ∴ / ∴ / ∴
|
||
'\u03d1': 'ϑ', # ϑ / ϑ / ϑ / ϑ
|
||
'\u25b5': '▵', # ▵ / utri / triangle
|
||
'\u225c': '≜', # ≜ / trie / triangleq
|
||
'\u21c5': '⇅', # ⇅ / udarr / UpArrowDownArrow
|
||
'\u296e': '⥮', # ⥮ / udhar / UpEquilibrium
|
||
'\u231c': '⌜', # ⌜ / ulcorn / ulcorner
|
||
'\u228e': '⊎', # ⊎ / uplus / UnionPlus
|
||
'\u2195': '↕', # ↕ / varr / updownarrow / UpDownArrow
|
||
'\u21c8': '⇈', # ⇈ / uuarr / upuparrows
|
||
'\u231d': '⌝', # ⌝ / urcorn / urcorner
|
||
'\u2016': '‖', # ‖ / Vert / Verbar
|
||
|
||
'\u2240': '≀', # ≀ / wr / wreath / VerticalTilde
|
||
'\u2128': 'ℨ', # ℨ / Zfr / zeetrf
|
||
}
|
||
|
||
# === Динамическая генерация карт преобразования ===
|
||
|
||
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 |