Files
2025-etpgrf/README.md

237 lines
21 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

| in progress // в процессе разработки |
|--------------------------------------|
| --------> |
# Типограф для Web
Экранная типографика для веба — способствует повышению читабельности текста в интернете,
приближая его к печатной типографике.
### Кодировки и html-мнемоники
Внутри типографа используется кодировка UTF-8. Но при использовании может быть другие кодировки (например,
для русскоязычных текстов все ещё могут использовать Windows-1251). При таких кодировках, для отображения в браузерах
некоторых специфических символов (например, кавычек, тире, стрелочек, математических символов) используют
html-мнемоники (например, `—` для длинного тире, `«` для открывающей кавычки-ёлочки и т.д.).
tpgrf имеет три режима работы с кодировками:
- Режим `unicode` — весь вывод осуществляется в кодировке UTF-8. ВЕСЬ! Включая невидимые символы, типа неразрывных и нулевых
пробелов, мягких переносов и т.д. Это не всегда удобно зато типографированый текст (строки) будет максимально
компактен и занимать меньше места в памяти. В этом режиме в html-мнемоники преобразуются только опасные символы:
* `&lt;` — знак меньше `<`;
* `&gt;` — знак больше `>`;
* `&amp;` — амперсанд `&`;
* `&quot;` — двойные кавычки `"`;
* `&apos;` — одинарные кавычки (апостроф) `'`.
- Режим `mixed` — вывод осуществляется в кодировке UTF-8, но наиболее критичные символы заменяются на html-мнемоники.
Они невидимы или неотличимы друг от друга на экране:
* `&shy;` — мягкий перенос (Soft Hyphen);
* `&nbsp;` — неразрывный пробел (Non-Breaking Space);
* `&ensp;` — полужирный пробел (En Space)
* `&emsp;` — широкий пробел (Em Space)
* `&numsp;` — цифровой пробел;
* `&puncsp;` — пунктуационный пробел;
* `&thinsp;` — межсимвольный пробел;
* `&hairsp;` — пробел "толщина волоса" (Hair Space);
* `&NegativeThinSpace;` — негативный пробел (Negative Space);
* `&zwj;` — пробел нулевой ширины (без объединения) (Zero Width Non-Joiner);
* `&zwnj;` — нулевая ширина (с объединением) (Zero Width Joiner);
* `&lrm;` — изменение направления текста на слева-направо (Left-to-Right Mark);
* `&rlm;` — изменение направления текста на направо-налево (Right-to-Left Mark);
* `&dash;` — дефис (Hyphen);
* `&MediumSpace;` — средний пробел (Medium Mathematical Space);
* `&NoBreak;` — неразрывный пробел (No-Break Space);
* `&InvisibleTimes;` — невидимый знак умножения (Invisible Times) для семантической разметки математических
выражений;
* `&InvisibleComma;` — невидимая запятая (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-мнемоник. Например, `→` (стрелочка влево) может кодироваться
как `&rarr;`, `&srarr;`, `&rightarrow`, `&RightArrow;` и `&ShortRightArrow;`. Типограф будет использовать самое
короткое из них (для компактности), а значит:
* если в исходном тексте были html-мнемоники, то они будут заменены на более короткие;
* если html-мнемоники использовались как элементы семантической разметки (например, для математических выражений),
то после замены на более короткие html-мнемоники, текст может потерять такую семантику. Например _F = A ⋂ B_:
`F = A &Intersection; B` будет преобразовано в `F = A &xcap; B`;
3. Мнемоники для русских букв не используются в типографе. Все мнемоники русских букв будут преобразованы в русские
буквы и останутся в тексте в виде русских букв.
4. Все исходные html-мнемоники, которые превращаются в два unicode-символа будут превращены обратно в мнемоники каждый
как отдельный символ. Например, множество собственное другого подмножества `&varsubsetneq;` в unicode отображается
двумя символами `\u228a\ufe00` и превратится в `&subne;\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
Электрофо&shy;ретическое исследование характе&shy;ризуется квинтэс&shy;сенциальной значимостью!
```
### Предлоги, союзы и частицы
Правилом хорошего тона в любой типографике считается, когда короткие слова, такие как предлоги, союзы и частицы,
не остаются в конце строки в одиночестве («висеть»). Это ухудшает читаемость.
Типограф `etpgrf` автоматически решает эту проблему, «приклеивая» такие слова к последующему слову с помощью
неразрывного пробела (`&nbsp;`).
* `в доме``в&nbsp;доме`
* `и сказал``и&nbsp;сказал`
Это правило работает для коротких слов в русском, старорусском и английском языках.
Кроме того, обрабатываются и постпозитивные частицы (например, `ли`, `же`, `бы`), которые, наоборот, для улучшения
читабельности, «приклеиваются» к предыдущему слову:
* `сказал бы``сказал&nbsp;бы`
### Кавычки
В текстах кавычки бывают двух видов: «ёлочки» (для русского языка) и “лапки” (для английского языка). В типографе
реализована автоматическая замена кавычек на соответствующие типографские символы в зависимости от языка текста.
Большинство типографов при обработке кавычек находят парные (и определяют вложенность). В 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 заменяет пробел перед тире на неразрывный (&nbsp;).
* `слово — слово``слово&nbsp;— слово`
В английской типографике, наоборот, тире пишется слитно. Типограф учитывает это при указании языка `langs='en'`.
* `word — word``word—word`
Если минус или диапазон стоят между числами (арабскими или римскими), то это считается обозначением числового диапазона
(или отрицательным числом, или математическим выражением), и никаких изменений не производится. Неважно есть пробелы
вокруг тире/минуса или нет. Если между цифрами тире, то это тоже считается диапазоном и неразрывные пробелы не ставятся:
`1941 — 1945``1941 — 1945`, `-10 — -5``-10 — -5`,
Если минус стоит перед числом (например, `-5`), то это считается отрицательным числом, и перед ним ставится неразрывный
пробел: `от -5 до +5``от&nbsp;-5 до +5`.
#### Инициалы и акронимы
Чтобы инициалы не отрывались друг от друга и от фамилии при переносе строки, типограф расставляет между ними
специальные пробелы:
* Неразрывный пробел (`&nbsp;`) ставится между фамилией и инициалом/инициалами (`А. Пушкин``А.&nbsp;Пушкин`).
Неважно стоят ли инициалы перед фамилией или после нее. Важно наличие точки и буквы (инициала), написанного
с заглавной буквы.
* Тонкая шпация (&thinsp;) ставится между самими инициалами, если они написаны слитно, для улучшения внешнего вида
(`А.С.Пушкин``А.&thinsp;С.Пушкин`). Число инициалов не ограничено (`J.R.R. Tolkien``J.&thinsp;R.&thinsp;R.
Tolkien`), наличие или отсутствие пробелов между инициалами в исходном тексте неважно.
* Акронимы, написанные через точку (не слитно, например, **Н.Л.О.**), разделяются так же, как инициалы, через тонкую шпацию
(`Н.Л.О.``Н.&thinsp;Л.&thinsp;О.`). Наличие или отсутствие пробелов между буквами в исходном тексте неважно.
Это правило может давать побочные эффекты (в частности, тонкая шпация не явлеятся неразрывным пробелом, и в длинных
акронимах может привести к разрыву строки). Поэтому его обработку можно отключить с помощью параметра
`process_initials_and_acronyms`:
```python
typo = etpgrf.Typographer(process_initials_and_acronyms=False)
result = typo.process("А. С. Пушкин") # Останется без изменений
```
#### Единицы измерения
Типограф предотвращает отрыв единиц измерения от чисел, ставя между ним и предшествующей цифрой неразрывный пробел.
Это работает для:
* **Простых единиц:** `100 км``100&nbsp;км`, `-5 °C``-5&nbsp;°C`'
* **Составных единиц:** `120 кв. м.``120&nbsp;кв.&thinsp;м.`, `50 тыс. руб.``50&nbsp;тыс.&thinsp;руб.`
* **Единиц с предлогом:** `№ 5``№&nbsp;5`
* **Чисел, записанных и арабскими, и римскими цифрами:** `V век``V&nbsp;век`
* Если единицами изменений есть математические символы (например, умножение или деление): `10 км / ч``10&nbsp;км/ч`
(не важно есть пробелы вокруг `/` или нет).
Библиотека "знает" множество стандартных единиц для русского и английского языков. Но не все. Вы можете расширить этот
список, передав свои кастомные единицы через параметр `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 км/ч") # Останется без изменений
```