# 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