---: minor

This commit is contained in:
2026-03-07 02:14:25 +03:00
parent 913f28f2f3
commit c7d8b18c68
2 changed files with 22 additions and 23 deletions

View File

@@ -17,7 +17,7 @@
* [GitHub](https://github.com/erjemin/etpgrf) (Главное зеркало) * [GitHub](https://github.com/erjemin/etpgrf) (Главное зеркало)
* [GitVerse](https://gitverse.ru/erjemin/etpgrf) (Зеркало на GitVerse) * [GitVerse](https://gitverse.ru/erjemin/etpgrf) (Зеркало на GitVerse)
## Демострация / Demo ## Демонстрация / Demo
Работа etpgrf-типографа представлена по адресу: [typograph.cube2.ru](https://typograph.cube2.ru/). Подготовьте верстку Работа etpgrf-типографа представлена по адресу: [typograph.cube2.ru](https://typograph.cube2.ru/). Подготовьте верстку
вашего текста, сайтов, статей и постов к публикации в интернете за один клик. вашего текста, сайтов, статей и постов к публикации в интернете за один клик.
@@ -34,7 +34,7 @@ import etpgrf
# Создаем типограф с настройками по умолчанию # Создаем типограф с настройками по умолчанию
typo = etpgrf.Typographer(langs='ru') typo = etpgrf.Typographer(langs='ru')
# Обрабатываем текст # Обрабатываем текст
result = typo.process(text="\"Пример текста для типографирования!\" - сказал он.") result = typo.process(text="\"Пример текста для типографа!\" - сказал он.")
print(result) print(result)
``` ```
@@ -45,9 +45,9 @@ print(result)
некоторых специфических символов (например, кавычек, тире, стрелочек, математических символов) используют некоторых специфических символов (например, кавычек, тире, стрелочек, математических символов) используют
html-мнемоники (например, `—` для длинного тире, `«` для открывающей кавычки-ёлочки и т.д.). html-мнемоники (например, `—` для длинного тире, `«` для открывающей кавычки-ёлочки и т.д.).
tpgrf имеет три режима работы с кодировками: Библиотека etpgrf имеет три режима работы с кодировками:
- Режим `unicode` — весь вывод осуществляется в кодировке UTF-8. ВЕСЬ! Включая невидимые символы, типа неразрывных и нулевых - Режим `unicode` — весь вывод осуществляется в кодировке UTF-8. ВЕСЬ! Включая невидимые символы, типа неразрывных
пробелов, мягких переносов и т.д. Это не всегда удобно зато типографированый текст (строки) будет максимально и нулевых пробелов, мягких переносов и т.д. Это не всегда удобно зато типографированый текст (строки) будет максимально
компактен и занимать меньше места в памяти. В этом режиме в html-мнемоники преобразуются только опасные символы: компактен и занимать меньше места в памяти. В этом режиме в html-мнемоники преобразуются только опасные символы:
* `&lt;` — знак меньше `<`; * `&lt;` — знак меньше `<`;
* `&gt;` — знак больше `>`; * `&gt;` — знак больше `>`;
@@ -95,16 +95,15 @@ result = typo_mixed_mode.process(text="Этот текст будет обраб
короткое из них (для компактности), а значит: короткое из них (для компактности), а значит:
* если в исходном тексте были html-мнемоники, то они будут заменены на более короткие; * если в исходном тексте были html-мнемоники, то они будут заменены на более короткие;
* если html-мнемоники использовались как элементы семантической разметки (например, для математических выражений), * если html-мнемоники использовались как элементы семантической разметки (например, для математических выражений),
то после замены на более короткие html-мнемоники, текст может потерять такую семантику. Например _F = A ⋂ B_: то после замены на более короткие html-мнемоники, текст может потерять такую семантику. Например `F = A &Intersection; B` (_F = A ⋂ B_) будет преобразовано в `F = A &xcap; B`;
`F = A &Intersection; B` будет преобразовано в `F = A &xcap; B`;
3. Мнемоники для русских букв не используются в типографе. Все мнемоники русских букв будут преобразованы в русские 3. Мнемоники для русских букв не используются в типографе. Все мнемоники русских букв будут преобразованы в русские
буквы и останутся в тексте в виде русских букв. буквы и останутся в тексте в виде русских букв.
4. Все исходные html-мнемоники, которые превращаются в два unicode-символа будут превращены обратно в мнемоники каждый 4. Все исходные html-мнемоники, которые превращаются в два unicode-символа будут превращены обратно в мнемоники каждый
как отдельный символ. Например, множество собственное другого подмножества `&varsubsetneq;` в unicode отображается как отдельный символ. Например, множество собственное другого подмножества `&varsubsetneq;` в unicode отображается
двумя символами `\u228a\ufe00` и превратится в `&subne;\ufe00`. Символ `\ufe00` — это невидимый символ, cелектор двумя символами `\u228a\ufe00` и превратится в `&subne;\ufe00`. Символ `\ufe00` — это невидимый символ, селектор
варианта начертания (Variant Selector), который изменяет начертание предыдущего символа и для него нет варианта начертания (Variant Selector), который изменяет начертание предыдущего символа и для него нет
html-мнемоники. К счастью, в стандарте таких мнемоник (превращающихся в два символа) исчезающе мало и они крайне html-мнемоники. К счастью, в стандарте таких мнемоник (превращающихся в два символа) исчезающе мало и они крайне
редко применляются в тексте, поэтому это не должно вызывать проблем. редко применяются в тексте, поэтому это не должно вызывать проблем.
### Переносы слов ### Переносы слов
@@ -171,7 +170,7 @@ result = typo_hyp.process(text="Электрофоретическое иссл
слева или справа от кавычки. слева или справа от кавычки.
Преобразование рядом с цифрами (например, когда обозначаются дюймы (`17"`) или секунды (`3' 25"`)) не производится. Также Преобразование рядом с цифрами (например, когда обозначаются дюймы (`17"`) или секунды (`3' 25"`)) не производится. Также
не обрабатываются кавычки окруженные пробелами. Все кавычки которые в исходном тексте уже были оформлены в виде не обрабатываются кавычки, окруженные пробелами. Все кавычки, которые в исходном тексте уже были оформлены в виде
«ёлочек» или “лапок” — тоже не обрабатываются. «ёлочек» или “лапок” — тоже не обрабатываются.
ВАЖНО1: По правилам орфографии перед закрывающей кавычкой разрешены только определенные знаки препинания: ВАЖНО1: По правилам орфографии перед закрывающей кавычкой разрешены только определенные знаки препинания:
@@ -183,7 +182,7 @@ result = typo_hyp.process(text="Электрофоретическое иссл
кавычкой.** кавычкой.**
ВАЖНО2: Если в настройке типографа указано несколько языков (`langs='ru+en'`), то кавычки будут преобразованы по правилам ВАЖНО2: Если в настройке типографа указано несколько языков (`langs='ru+en'`), то кавычки будут преобразованы по правилам
для языка который идет первым в списке. Например, для `langs='ru+en'` кавычки будут преобразованы в «ёлочки», для языка, который идет первым в списке. Например, для `langs='ru+en'` кавычки будут преобразованы в «ёлочки».
Если при типорафировании преобразование не требуется, то можно обработку кавычек можно отключить с помощью Если при типорафировании преобразование не требуется, то можно обработку кавычек можно отключить с помощью
параметра `quotes=False`: параметра `quotes=False`:
@@ -202,8 +201,8 @@ result = typo_no_quotes.process(text='Этот "текст" будет обра
#### Тире #### Тире
По правилам русской типографики, длинное тире () должно отбиваться пробелами от соседних слов. Чтобы тире не "повисло" По правилам русской типографики, длинное тире (`—`) должно отбиваться пробелами от соседних слов. Чтобы тире не "повисло"
в начале строки и визуально не смешивалось с диалогами, etpgrf заменяет пробел перед тире на неразрывный (&nbsp;). в начале строки и визуально не смешивалось с диалогами, etpgrf заменяет пробел перед тире на неразрывный (`&nbsp;`).
* `слово — слово``слово&nbsp;— слово` * `слово — слово``слово&nbsp;— слово`
@@ -227,7 +226,7 @@ result = typo_no_quotes.process(text='Этот "текст" будет обра
* Неразрывный пробел (`&nbsp;`) ставится между фамилией и инициалом/инициалами (`А. Пушкин``А.&nbsp;Пушкин`). * Неразрывный пробел (`&nbsp;`) ставится между фамилией и инициалом/инициалами (`А. Пушкин``А.&nbsp;Пушкин`).
Неважно стоят ли инициалы перед фамилией или после неё. Важно наличие точки и буквы (инициала), написанного Неважно стоят ли инициалы перед фамилией или после неё. Важно наличие точки и буквы (инициала), написанного
с заглавной буквы. с заглавной буквы.
* Тонкая шпация (&thinsp;) ставится между самими инициалами, если они написаны слитно, для улучшения внешнего вида * Тонкая шпация (`&thinsp;`) ставится между самими инициалами, если они написаны слитно, для улучшения внешнего вида
(`Пушкин А. С. ``Пушкин&nbsp;А.&thinsp;С.`). Число инициалов не ограничено (`J.R.R. Tolkien` (`Пушкин А. С. ``Пушкин&nbsp;А.&thinsp;С.`). Число инициалов не ограничено (`J.R.R. Tolkien`
`J.&thinsp;R.&thinsp;R.&nbsp;Tolkien`), наличие или отсутствие пробелов между инициалами в исходном тексте неважно. `J.&thinsp;R.&thinsp;R.&nbsp;Tolkien`), наличие или отсутствие пробелов между инициалами в исходном тексте неважно.
* Акронимы, написанные через точку (не слитно, например, **Н.Л.О.**), разделяются так же, как инициалы, через тонкую шпацию * Акронимы, написанные через точку (не слитно, например, **Н.Л.О.**), разделяются так же, как инициалы, через тонкую шпацию
@@ -262,7 +261,7 @@ result = typo.process("А. С. Пушкин") # Останется без изм
```python ```python
# Передаем список # Передаем список
typo = etpgrf.Typographer(process_units=['бочек', 'вёдер']) typo = etpgrf.Typographer(process_units=['бочек', 'вёдер'])
# Можно передавать и с помощзью строки через пробелы # Можно передавать и с помощью строки через пробелы
typo = etpgrf.Typographer(process_units='бочек вёдер аршин сажен') typo = etpgrf.Typographer(process_units='бочек вёдер аршин сажен')
result = typo.process("Нужно 10 бочек.") # -> "Нужно 10&nbsp;бочек." result = typo.process("Нужно 10 бочек.") # -> "Нужно 10&nbsp;бочек."
``` ```
@@ -294,7 +293,7 @@ result = typo.process("100 км/ч") # Останется без
### Висячая типографика ### Висячая типографика
Висячая типографика — это приём из классической вёрстки, когда некоторые знаки препинания (кавычки, скобки, иногда Висячая типографика — это приём из классической вёрстки, когда некоторые знаки препинания (кавычки, скобки, иногда
tире и маркеры списков) выносятся на левое (и иногда и по правому) поле текста. Это создаёт идеально ровный край не по тире и маркеры списков) выносятся на левое (и иногда и по правому) поле текста. Это создаёт идеально ровный край не по
формальным границам знаков, а по оптическому краю — по первым буквам строк. Текст выглядит гораздо аккуратнее и формальным границам знаков, а по оптическому краю — по первым буквам строк. Текст выглядит гораздо аккуратнее и
профессиональнее. профессиональнее.
@@ -308,7 +307,7 @@ Safari), поэтому на него полагаться нельзя. Поэ
Оборачивая "висячий" символ или слово в `<span>` и применяя к нему, например, отрицательный `text-indent` или Оборачивая "висячий" символ или слово в `<span>` и применяя к нему, например, отрицательный `text-indent` или
`margin-left` (`<span style="margin-left:-0.44em">&laquo;</span>`), мы можем сместить сам символ, но нужно ещё и `margin-left` (`<span style="margin-left:-0.44em">&laquo;</span>`), мы можем сместить сам символ, но нужно ещё и
сохранить расстояние до соседнего слова. Поэтому типограф оборачивает не только сам висячий символ, но и ближайшее слово сохранить расстояние до соседнего слова. Поэтому типограф оборачивает не только сам висячий символ, но и ближайшее слово
(до пробела или границы узла), а также, при необходимости, окружающий пробел. Сама визуальная компенсация оформляется через (до пробела или границы узла), а также при необходимости, окружающий пробел. Сама визуальная компенсация оформляется через
отрицательные `margin`/`padding` в CSS-классах — никаких `position:absolute`, чтобы не нарушать поток текста. отрицательные `margin`/`padding` в CSS-классах — никаких `position:absolute`, чтобы не нарушать поток текста.
По умолчанию эта функция висячей типографики **отключена**. Чтобы её включить, нужно задать параметр По умолчанию эта функция висячей типографики **отключена**. Чтобы её включить, нужно задать параметр
@@ -327,7 +326,7 @@ typo = etpgrf.Typographer(hanging_punctuation='left')
с размещением пробелов и делает невозможным контролировать визуальное выравнивание (см. блок про `text-justify`). с размещением пробелов и делает невозможным контролировать визуальное выравнивание (см. блок про `text-justify`).
Также через `hanging_punctuation` можно задать список тегов, внутри которых висячая типографика будет применяться Также через `hanging_punctuation` можно задать список тегов, внутри которых висячая типографика будет применяться
(всегда в режиме `'both'`). Это нерекомендованный способ, потому что он предполагает знание структуры HTML и неизбежно (всегда в режиме `'both'`). Это не рекомендованный способ, потому что он предполагает знание структуры HTML и неизбежно
выпадает из общей логики вложенности и пробельных узлов. выпадает из общей логики вложенности и пробельных узлов.
### Как работает оборачивание ### Как работает оборачивание
@@ -340,7 +339,7 @@ typo = etpgrf.Typographer(hanging_punctuation='left')
слово (`<span class="etp-laquo">«АукЫон»</span>`); слово (`<span class="etp-laquo">«АукЫон»</span>`);
* если перед символом внутри узла есть пробел, то пробел оборачивается в `<span class="etp-sp-laquo"> </span>`, а * если перед символом внутри узла есть пробел, то пробел оборачивается в `<span class="etp-sp-laquo"> </span>`, а
символ вместе со словом — в `<span class="etp-laquo">...</span>`; символ вместе со словом — в `<span class="etp-laquo">...</span>`;
* если пробел оказалось в соседнем узле, то он тоже оборачивается в `etp-sp-*`, чтобы не нарушить последовательность; * если пробел оказался в соседнем узле, то он тоже оборачивается в `etp-sp-*`, чтобы не нарушить последовательность;
* если компенсирующий пробел является "непереносимым пробелом" (или любым другим: шпацией, em-пробелом и т.п.), то тогда, для правильного выравнивания, оборачивается он, например: `<span class="etp-sp-laquo">&nbsp;</span><span class="etp-laquo">«АукЫон»</span>`. * если компенсирующий пробел является "непереносимым пробелом" (или любым другим: шпацией, em-пробелом и т.п.), то тогда, для правильного выравнивания, оборачивается он, например: `<span class="etp-sp-laquo">&nbsp;</span><span class="etp-laquo">«АукЫон»</span>`.
* Для `hanging_punctuation='right'`: * Для `hanging_punctuation='right'`:
* слово с висячим символом оборачивается в соответствующий класс (`.etp-raquo`, `.etp-rpar` и т.д.); * слово с висячим символом оборачивается в соответствующий класс (`.etp-raquo`, `.etp-rpar` и т.д.);
@@ -391,7 +390,7 @@ typo = etpgrf.Typographer(hanging_punctuation='left')
При обработке сложного HTML-кода типограф стремится сохранить структуру документа, но некоторые пограничные случаи могут обрабатываться не так, как ожидается. В частности: При обработке сложного HTML-кода типограф стремится сохранить структуру документа, но некоторые пограничные случаи могут обрабатываться не так, как ожидается. В частности:
* **Обработка на стыке тегов:** Правила, требующие анализа контекста (например, расстановка неразрывных пробелов у тире или единиц измерения), могут работать некорректно, если анализируемые части текста разделены тегами . Например, конструкция `$<b>100</b>` не будет обработана (между $ и 100 не будет вставлен неразрывный пробел), так как типограф не видит их как соседние элементы. * **Обработка на стыке тегов:** Правила, требующие анализа контекста (например, расстановка неразрывных пробелов у тире или единиц измерения), могут работать некорректно, если анализируемые части текста разделены тегами. Например, конструкция `$<b>100</b>` не будет обработана (между $ и 100 не будет вставлен неразрывный пробел), так как типограф не видит их как соседние элементы.
* **"Ремонт" HTML:** Библиотека использует `BeautifulSoup` для парсинга, который может "чинить" невалидный HTML (например, закрывать незакрытые теги). Это может привести к неожиданным изменениям в структуре, если исходный код был некорректен. Так же может меняться порядок атрибутов тега. * **"Ремонт" HTML:** Библиотека использует `BeautifulSoup` для парсинга, который может "чинить" невалидный HTML (например, закрывать незакрытые теги). Это может привести к неожиданным изменениям в структуре, если исходный код был некорректен. Так же может меняться порядок атрибутов тега.
Мы знаем об этих особенностях и работаем над улучшением алгоритмов для более точной обработки сложных случаев. Мы знаем об этих особенностях и работаем над улучшением алгоритмов для более точной обработки сложных случаев.

View File

@@ -71,9 +71,9 @@ TYPOGRAPHER_HTML_TEST_CASES = [
f'<p>Он{CHAR_NBSP}сказал: «В{CHAR_NBSP}1941{CHAR_NDASH}1945{CHAR_NBSP}гг.{CHAR_NBSP}{CHAR_NDASH} было' f'<p>Он{CHAR_NBSP}сказал: «В{CHAR_NBSP}1941{CHAR_NDASH}1945{CHAR_NBSP}гг.{CHAR_NBSP}{CHAR_NDASH} было'
f' 100{CHAR_NBSP}тыс.{CHAR_THIN_SP}руб. и{CHAR_NBSP}т.{CHAR_THIN_SP}д.»</p>'), f' 100{CHAR_NBSP}тыс.{CHAR_THIN_SP}руб. и{CHAR_NBSP}т.{CHAR_THIN_SP}д.»</p>'),
# --- Теги внутри кавычек --- # --- Теги внутри кавычек ---
('mnemonic', '<p>"<u>Почему</u>", "<u>зачем</u>" и "<u>кому это выгодно</u>" -- вопросы требующие ответа.</p>', ('mnemonic', '<p>"<u>Почему</u>", "<u>зачем</u>" и "<u>кому это выгодно</u>" -- вопросы, требующие ответа.</p>',
'<p>&laquo;<u>Почему</u>&raquo;, &laquo;<u>зачем</u>&raquo; и&nbsp;&laquo;<u>кому это выгодно</u>' '<p>&laquo;<u>Почему</u>&raquo;, &laquo;<u>зачем</u>&raquo; и&nbsp;&laquo;<u>кому это выгодно</u>'
'&raquo;&nbsp;&ndash; вопросы требующие ответа.</p>'), '&raquo;&nbsp;&ndash; вопросы, требующие ответа.</p>'),
('mixed', '<p>"<u>Почему</u>", "<u>зачем</u>" и "<u>кому это выгодно</u>" -- вопросы требующие ответа.</p>', ('mixed', '<p>"<u>Почему</u>", "<u>зачем</u>" и "<u>кому это выгодно</u>" -- вопросы требующие ответа.</p>',
'<p>«<u>Почему</u>», «<u>зачем</u>» и&nbsp;«<u>кому это выгодно</u>»&nbsp; вопросы требующие ответа.</p>'), '<p>«<u>Почему</u>», «<u>зачем</u>» и&nbsp;«<u>кому это выгодно</u>»&nbsp; вопросы требующие ответа.</p>'),
('unicode', '<p>"<u>Почему</u>", "<u>зачем</u>" и "<u>кому это выгодно</u>" -- вопросы требующие ответа.</p>', ('unicode', '<p>"<u>Почему</u>", "<u>зачем</u>" и "<u>кому это выгодно</u>" -- вопросы требующие ответа.</p>',
@@ -86,7 +86,7 @@ TYPOGRAPHER_HTML_TEST_CASES = [
# --- Самозакрывающиеся теги и теги с атрибутами --- # --- Самозакрывающиеся теги и теги с атрибутами ---
# ВАЖНО: 1. Порядок атрибутов в типографированном тексте может быть произвольным # ВАЖНО: 1. Порядок атрибутов в типографированном тексте может быть произвольным
# 2. Любое число пробельных символов внутри "пустых" тегов будут редуцированы до одного пробела или # 2. Любое число пробельных символов внутри "пустых" тегов будет редуцировано до одного пробела или
# перевода строки. # перевода строки.
# 3. Самозакрывающиеся теги будут приведены к единому виду с косой чертой в конце. Типа <br/> # 3. Самозакрывающиеся теги будут приведены к единому виду с косой чертой в конце. Типа <br/>
# 4. Все это "проделки" связаны с использованием библиотеки BeautifulSoup для парсинга HTML, # 4. Все это "проделки" связаны с использованием библиотеки BeautifulSoup для парсинга HTML,