| in progress // в процессе разработки | |--------------------------------------| | --------> | # Типограф для Web Экранная типографика для веба — способствует повышению читабельности текста в интернете, приближая его к печатной типографике. ### Кодировки и html-мнемоники Внутри типографа используется кодировка UTF-8. Но при использовании может быть другие кодировки (например, для русскоязычных текстов все ещё могут использовать Windows-1251). При таких кодировках, для отображения в браузерах некоторых специфических символов (например, кавычек, тире, стрелочек, математических символов) используют html-мнемоники (например, `—` для длинного тире, `«` для открывающей кавычки-ёлочки и т.д.). tpgrf имеет три режима работы с кодировками: - Режим `unicode` — весь вывод осуществляется в кодировке UTF-8. ВЕСЬ! Включая невидимые символы, типа неразрывных и нулевых пробелов, мягких переносов и т.д. Это не всегда удобно зато типографированый текст (строки) будет максимально компактен и занимать меньше места в памяти. В этом режиме в html-мнемоники преобразуются только опасные символы: * `<` — знак меньше `<`; * `>` — знак больше `>`; * `&` — амперсанд `&`; * `"` — двойные кавычки `"`; * `'` — одинарные кавычки (апостроф) `'`. - Режим `mixed` — вывод осуществляется в кодировке UTF-8, но наиболее критичные символы заменяются на html-мнемоники. Они невидимы или неотличимы друг от друга на экране: * `­` — мягкий перенос (Soft Hyphen); * ` ` — неразрывный пробел (Non-Breaking Space); * ` ` — полужирный пробел (En Space) * ` ` — широкий пробел (Em Space) * ` ` — цифровой пробел; * ` ` — пунктуационный пробел; * ` ` — межсимвольный пробел; * ` ` — пробел "толщина волоса" (Hair Space); * `​` — негативный пробел (Negative Space); * `‍` — пробел нулевой ширины (без объединения) (Zero Width Non-Joiner); * `‌` — нулевая ширина (с объединением) (Zero Width Joiner); * `‎` — изменение направления текста на слева-направо (Left-to-Right Mark); * `‏` — изменение направления текста на направо-налево (Right-to-Left Mark); * `‐` — дефис (Hyphen); * ` ` — средний пробел (Medium Mathematical Space); * `⁠` — неразрывный пробел (No-Break Space); * `⁢` — невидимый знак умножения (Invisible Times) для семантической разметки математических выражений; * `⁣` — невидимая запятая (Invisible Comma) для семантической разметки математических выражений. - Режим `mnemonic` — применяются все возможные html-мнемоники (кроме русских букв) и символов первой половины ASCII (плюс, минус, знак равенства, знаки препинания и т.д.). Переключение режимов осуществляется с помощью параметра `mode` при конфигурировании типографа: ```python # Задаем конфигурацию типографа typo_mixed_mode = etpgrf.Typographer(mode='mixed') # Обработка текста result = typo_mixed_mode.process(text="Этот текст будет обработан в режиме mixed.") ``` ### ВАЖНО: 1. Если в тексте уже есть html-мнемоники, они будут преобразованы в unicode, и после обработки типографом будут заменены на html-мнемоники, соответствующие текущему режиму работы типографа. 2. Некоторым символам соответствуют несколько html-мнемоник. Например, `→` (стрелочка влево) может кодироваться как `→`, `→`, `&rightarrow`, `→` и `→`. Типограф будет использовать самое короткое из них (для компактности), а значит: * если в исходном тексте были html-мнемоники, то они будут заменены на более короткие; * если html-мнемоники использовались как элементы семантической разметки (например, для математических выражений), то после замены на более короткие html-мнемоники, текст может потерять такую семантику. Например _F = A ⋂ B_: `F = A ⋂ B` будет преобразовано в `F = A ⋂ B`; 3. Мнемоники для русских букв не используются в типографе. Все мнемоники русских букв будут преобразованы в русские буквы и останутся в тексте в виде русских букв. 4. Все исходные html-мнемоники, которые превращаются в два unicode-символа будут превращены обратно в мнемоники каждый как отдельный символ. Например, множество собственное другого подмножества `⊊︀` в unicode отображается двумя символами `\u228a\ufe00` и превратится в `⊊\ufe00`. Символ `\ufe00` — это невидимый символ, cелектор варианта начертания (Variant Selector), который изменяет начертание предыдущего символа и для него нет html-мнемоники. К счастью, в стандарте таких мнемоник (превращающихся в два символа) исчезающе мало и они крайне редко применяются в тексте, поэтому это не должно вызывать проблем. ### Переносы слов Обычно в основе переносов слов лежит фонетический принцип — деление по слогам и морфемный принцип — деление по морфемам (приставки, корни, суффиксы, окончания). В типографе etpgrf реализован эвристический подход к переносу слов, основанный на фонетических правилах. Он не является строгим и не учитывает все нюансы языка, но обеспечивает вполне приемлемое качество для большинства случаев. Особенно если "неразрывные" блоки задать достаточно длинными (и именно это и требуется от хорошего типографа, ведь перенос трех-четырех букв слова на новую строку почти не улучшит читабельность и внешний вид текста). Настройки по умолчанию для переноса слов (в `etpgrf.defaults`): * Длина слова которое не подлежит переносам (`MAX_UNHYPHENATED_LEN`) — 12 символов. * Длина части слова, которое недопустимо переносить или оставлять на строке ("хвост", "сироты") (`MIN_TAIL_LEN`) — 5 символов Управление этими параметрами осуществляется через переопределение. Например: ```python # Меняем настройки по умолчанию для переносов etpgrf.defaults.etpgrf_settings.hyphenation.MAX_UNHYPHENATED_LEN = 8 etpgrf.defaults.etpgrf_settings.hyphenation.MIN_TAIL_LEN = 4 ``` Или через параметры конфигурации переносов типографа: ```python # Определяем пользовательские правила переносов hyphen_settings = etpgrf.Hyphenator(langs='ru', max_unhyphenated_len=8) # Передаем их в типограф typo_hyp = etpgrf.Typographer(langs='ru', mode='mnemonic', hyphenation=hyphen_settings) # Обработка текста с переносами result = typo_hyp.process(text="Электрофоретическое исследование характеризуется квинтэссенциальной значимостью!") ``` Результат обработки текста с переносами будет выглядеть так: ```html Электрофо­ретическое исследование характе­ризуется квинтэс­сенциальной значимостью! ``` ### Предлоги, союзы и частицы Правилом хорошего тона в любой типографике считается, когда короткие слова, такие как предлоги, союзы и частицы, не остаются в конце строки в одиночестве («висеть»). Это ухудшает читаемость. Типограф `etpgrf` автоматически решает эту проблему, «приклеивая» такие слова к последующему слову с помощью неразрывного пробела (` `). * `в доме` → `в доме` * `и сказал` → `и сказал` Это правило работает для коротких слов в русском, старорусском и английском языках. Кроме того, обрабатываются и постпозитивные частицы (например, `ли`, `же`, `бы`), которые, наоборот, для улучшения читабельности, «приклеиваются» к предыдущему слову: * `сказал бы` → `сказал бы` ### Кавычки В текстах кавычки бывают двух видов: «ёлочки» (для русского языка) и “лапки” (для английского языка). В типографе реализована автоматическая замена кавычек на соответствующие типографские символы в зависимости от языка текста. Большинство типографов при обработке кавычек находят парные (и определяют вложенность). В etpgrf же реализован другой подход. Он ищет и обрабатывает кавычки, которые находятся рядом со словами. То есть какие-то буквы следуют слева или справа от кавычки. Преобразование рядом с цифрами (например, когда обозначаются дюймы (`17"`) или секунды (`3' 25"`)) не производится. Также не обрабатываются кавычки окруженные пробелами. Все кавычки которые в исходном тексте уже были оформлены в виде «ёлочек» или “лапок” — тоже не обрабатываются. ВАЖНО1: По правилам орфографии перед закрывающей кавычкой разрешены только определенные знаки препинания: вопросительный (?), восклицательный (!) знаки и многоточие (…). Такие конструкции используются для цитат. Это учтено в etpgrf, и кавычки будут обработаны: `Она воскликнула: "Какая красота!"` будет преобразовано в `Она воскликнула: «Какая красота!»`. В неправильны конструкциях (например, `"Какая красота."`) закрывающая кавычка не будет обработана. ВАЖНО2: Если в настройке типографа указано несколько языков (`langs='ru+en'`), то кавычки будут преобразованы по правилам для языка который идет первым в списке. Например, для `langs='ru+en'` кавычки будут преобразованы в «ёлочки», Если при типорафировании преобразование не требуется, то можно обработку кавычек можно отключить с помощью параметра `quotes=False`: ```python # Задаем конфигурацию типографа без кавычек typo_no_quotes = etpgrf.Typographer(langs='ru', quotes=False) # Обработка текста без кавычек result = typo_no_quotes.process(text='Этот "текст" будет обработан без кавычек.') ``` ### Компоновка (тире, диапазоны, инициалы, единицы измерения, сокращения и т.п.) После того как псевдографика заменена на правильные символы, в дело вступает модуль компоновки (layout), который отвечает за расстановку неразрывных и тонких пробелов. Он применяет несколько важных правил для улучшения читаемости. #### Тире По правилам русской типографики, длинное тире (—) должно отбиваться пробелами от соседних слов. Чтобы тире не "повисло" в начале строки и визуально не смешивалось с диалогами, etpgrf заменяет пробел перед тире на неразрывный ( ). * `слово — слово` → `слово — слово` В английской типографике, наоборот, тире пишется слитно. Типограф учитывает это при указании языка `langs='en'`. * `word — word` → `word—word` Если минус или диапазон стоят между числами (арабскими или римскими), то это считается обозначением числового диапазона (или отрицательным числом, или математическим выражением), и никаких изменений не производится. Неважно есть пробелы вокруг тире/минуса или нет. Если между цифрами тире, то это тоже считается диапазоном и неразрывные пробелы не ставятся: `1941 — 1945` → `1941 — 1945`, `-10 — -5` → `-10 — -5`, Если минус стоит перед числом (например, `-5`), то это считается отрицательным числом, и перед ним ставится неразрывный пробел: `от -5 до +5` → `от -5 до +5`. #### Инициалы и акронимы Чтобы инициалы не отрывались друг от друга и от фамилии при переносе строки, типограф расставляет между ними специальные пробелы: * Неразрывный пробел (` `) ставится между фамилией и инициалом/инициалами (`А. Пушкин` → `А. Пушкин`). Неважно стоят ли инициалы перед фамилией или после неё. Важно наличие точки и буквы (инициала), написанного с заглавной буквы. * Тонкая шпация ( ) ставится между самими инициалами, если они написаны слитно, для улучшения внешнего вида (`Пушкин А. С. ` → `Пушкин А. С.`). Число инициалов не ограничено (`J.R.R. Tolkien` → `J. R. R. Tolkien`), наличие или отсутствие пробелов между инициалами в исходном тексте неважно. * Акронимы, написанные через точку (не слитно, например, **Н.Л.О.**), разделяются так же, как инициалы, через тонкую шпацию (`Н.Л.О.` → `Н. Л. О.`). Наличие или отсутствие пробелов между буквами в исходном тексте неважно. Это правило может давать побочные эффекты (в частности, тонкая шпация не является неразрывным пробелом, и в длинных акронимах может привести к разрыву строки). Поэтому его обработку можно отключить с помощью параметра `process_initials_and_acronyms`: ```python typo = etpgrf.Typographer(process_initials_and_acronyms=False) result = typo.process("А. С. Пушкин") # Останется без изменений ``` #### Единицы измерения Типограф предотвращает отрыв единиц измерения от чисел, ставя между ним и предшествующей цифрой неразрывный пробел. Это работает для: * **Простых единиц:** `100 км.` → `100 км.`, `-5 °C` → `-5 °C`' * **Составных единиц:** `120 кв.м.` → `120 кв. м.`, `50 тыс. руб.` → `50 тыс. руб.` Пробелы (есть они или нет) между составными частями единицы изменения не важны. Между частями составной единицы измерения ставится тонкая шпация (` `). * **Единиц с предлогом:** `№ 5` → `№ 5`, `§ 7` → `§ 7`, `$ 100` → `$ 100` * **Чисел, записанных и арабскими, и римскими цифрами:** `V в.н.э.` → `V в. н. э.` * Если между единицами изменений есть математические символы (например, умножение или деление): `10 км / ч` → `10 км/ч` (неважно есть пробелы вокруг `/` или нет). Распознаются и другие символы: `·`, `*`, `×`, `÷`. Библиотека "знает" множество стандартных единиц для русского и английского языков. Но не все. Вы можете расширить этот список, передав свои кастомные единицы через параметр `process_units`: ```python # Передаем список typo = etpgrf.Typographer(process_units=['бочек', 'вёдер']) # Можно передавать и с помощзью строки через пробелы typo = etpgrf.Typographer(process_units='бочек вёдер аршин сажен') result = typo.process("Нужно 10 бочек.") # -> "Нужно 10 бочек." ``` Если нужно отключить распознавание и обработку единиц измерения: ```python typo = etpgrf.Typographer(process_units=False) result = typo.process("100 км/ч") # Останется без изменений ``` ## P.S. Если вам нравится этот проект и хотите поддержать его, можете отправить любую сумму на мой Т-банк [по ссылке](https://tbank.ru/cf/27hMw1BTFMs) или QR-коду. ![Сбор средств](qr-code.png) Средства пойдут на улучшение моего настроения путем покупки виниловых пластинок. В списке желаний: | Bar-Code | Artist | Album | Format | | | Label | Цена | | |---------------|--------------------------|-----------------------------------------|--------|-------------------------|------------|---------------|---------|---| | 0711297924305 | SUZANNE VEGA | Flying With Angels | LP | Grey Smoke | 02.05.2025 | Cooking Vinyl | ₽ 4099 | + | | 0602475914716 | CRANBERRIES | No Need To Argue | 2LP | 30th Ann, Deluxe | 15.08.2025 | Island | ₽ 5499 | + | | ATL 40 022 | IRON BUTTERFLY | In-A-Gadda-Da-Vida | LP | NM/NM, Germany (винтаж) | 1973 | Atlantic | ₽ 2499 | + | | 5400863145637 | EELS | So Good | LP | coloured | 15.12.2023 | | ₽ 4360 | | 5400863157845 | EELS | Time! | LP | coloured | 07.06.2024 | | ₽ 4940 | | 8719262034853 | NICK CAVE & WARREN ELLIS | Mars (Original Sound Track) | LP | coloured | 12.07.2024 | | ₽ 3440 | | 5021732526007 | GORILLAZ | Demon Days Live From The Apollo Theater | 2LP | RSD2025, Red | 12.04.2025 | Warner | ₽ 5999 | | 5021732526007 | GORILLAZ | TOMORROW COMES TODAY | EP 12" | color (white & blue) | 20.06.2025 | | ₽ 3600 |