,'``.._ ,'``. :,--._:)\,:,._,.: All Glory to :`--,'' :`...';\ the HYPNO TOAD! `,' `---' `. / : / \ ,' :\.___,-. `...,---'``````-..._ |: \ ( ) ;: ) \ _,-. `. ( // `' \ : `.// ) ) , ; ,-|`. _,'/ ) ) ,' ,' ( :`.`-..____..=:.-': . _,' ,' `,'\ ``--....-)=' `._, \ ,') _ '``._ _.-/ _ `. (_) / )' ; / \ \`-.' `--( `-:`. `' ___..' _,-' |/ `.) `-. `.`.``-----``--, .' |/`.\`' ,','); SSt ` (/ (/
Найдено в интернетах.
Всем привет!
Хочу поделиться своей небольшой разработкой: типографом, который можно использовать локально.
Дисклеймер
Проект находится в стадии разработки и нуждается в тщательном тестировании.
Возможности
- замена кавычек на
«„“»и“‘’”(в английской версии). Число уровней не ограничено — типограф просто черед��ет четные/нечетные — где-какие можно настроить - расстановка дюймов, апострофов:
4′,20″ - комплексные символы: многоточие, копирайты, трейдмарки, стрелочки и т. д.:
(c)становится ``, причем, даже если написано кириллицей - замена дефисов на длинное тире в текстах и числовых диапазонах
- замена дефисов на короткое тире в номерах телефонов
- расстановка минусов и знаков умножения
- связывание чисел с последующими словами неразрывным дефисом, например
40 попугаев - связывание союзов и любых слов из 1-2 символов с последующими словами
- отделение единиц измерения от чисел (возможно, выпилю в скором будущем, очень велик шанс ложно-положительного результата)
- неразрывные пробелы в сокращениях:
т.д.станетт. д.;А. С. Пушкин— здесь обычный пробел станет разрывным - замена
рируб(с точкой в конце и без) на символ рубля — возможно выпилю, поскольку удалит точку если найдет совпадение в конце предложения - замена дробей
1/2,1/3и т.д. на существующие символы юникода - удаление лишних пробелов и переносов строк, тримминг вначале и вконце
- расстановка неразрывных пробелов в куче случаев
- не влияет на html теги и игнорирует содержимое
(head|iframe|pre|code|script|style) - можно передать строки, которые типограф будет игнорировать
Пример
from typus import ru_typus ru_typus('00" "11 \'22\' 11"? "11 \'22 "33 33?"\' 11" 00 "11 \'22\' 11" 0"') '00″ «11 „22“ 11»? «11 „22 «33 33?»“ 11» 00 «11 „22“ 11» 0″'
Число — уровень вложенности. Если бы первая кавычка стояла до нулей, был бы еще один уровень, а так вышли дюймы.
Как устроен
class BaseTypus(EnRuExpressions, TypusCore): processors = (EscapePhrases, EscapeHtml, TypoQuotes, Expressions) class RuTypus(RuQuotes, BaseTypus): pass ru_typus = RuTypus()
Typus состоит из "процессоров" и "выражений".
Выражения
Это пары (regex, replace), которые передаются в re.sub(regex, replace) и выполняются последовательно (см. чуть ниже). Почти весь типограф — это "выражения". Они записываются как методы с приставкой expr_, функция должна вернуть вложенный список, т.е. одно "выражение" может вернуть череду "выражений":
class MyTypus(Typus): expressions = Typus.expressions + 'http://bar' def expr_http://bar(self): expr = ( (r'\d', '@'), # заменяет числа на @ ) return expr
Третий, необязательный, аргумент — флаги передаваемые в re.compile, по-умолчанию, это re.I | re.U | re.M | re.S.
Кстати, replace может быть функцией, см. re.sub.
Чтобы определить последовательность используется атрибут типографа — expressions, который хранит список названий выражений. Можно выключить лишнее:
from typus import RuTypus exclude_expressions = ('ruble', 'math') class MyTypus(RuTypus): expressions = (e for e in RuTypus.expressions if e not in exclude_expressions)
expressions может быть генератором, но если сделать последовательностью, можно делать так:
def expr_http://bar(self): if 'some' in self.expressions: return baz return egg
В коробке идет лишь один микс выражений — EnRuExpressions, но он делает почти всю работу.
Для работы выражений используется процессор Expressions.
Процессоры
Иногда простыми регулярками не отделаться, приходится городить убер-функцию. Процессор это класс-функция-декоратор, который инициируется во время создания типографа, а затем вызывается при обработке текста. Ему (инстансу процессора) передается сам инстанс типографа, чтобы процессор мог получить доступ к его конфигурации.
При использовании нескольких процессоров, они декорируют друг-друга по порядку. Например, так:
удалить html теги дать ход следующему процессору, если сошлись звезды что-то там поделать с текстом обработать и вернуть наверх вернуть теги
С Typus поставляются несколько процессоров: EscapePhrases, EscapeHtml, TypoQuotes, Expressions.
EscapePhrases
Бывают случаи, когда определенный кусок текста обрабатывать нельзя, либо вы заранее знаете, что типограф на этом месте запнется, в таком случае можно поступить так:
typus('"http://bar 2""', escape_phrases=['2"']) '«http://bar 2"»'
Без этого типограф встретит закрывающую кавычку: «http://bar 2»". Еще пример:
typus('Типограф заменяет (c) на (c)', escape_phrases=['заменяет (c)']) 'Типограф заменяет (c) на '
Аргумент escape_phrases можно вынести отдельным полем в ваше CRUD приложение (ака "админку"), где контент менеджер сможет перечислить фразы через разделитель, а вы передадите их типографу.
Чтобы разделить текст можно можно воспользоваться утилитой:
from typus.utils import splinter split = splinter(',') split('a, b,c ') == ['a', 'b', 'c'] split('a, b\,c') == ['a', 'b,c']
splinter понимает экранированные разделители и вызывает str.strip() для каждой фразы.
EscapeHtml
Выразет html-теги до типографа и возвращает их после. Без него <img src="http://bar"> превратится в <img src=«http://bar»>.
TypoQuotes
Проставляет кавычки. Ожидает, что в типографе будут перечислены атрибуты loq, roq, leq, req. Пример:
from typus import BaseTypus from typus.chars import LAQUO, RAQUO, DLQUO, LDQUO class MyTypus(BaseTypus): # Лева нечетная, правая нечетная, левая четная, правая четная loq, roq, leq, req = LAQUO, RAQUO, DLQUO, LDQUO
Есть готовые миксины EnQuotes и RuQuotes в модуле typus.mixins.
Expressions
Обеспечивает работу выражений. Во время инициализации типографа все регулярки компилируются и хранятся в инстансе процессора.
Про отладку
Если типографу передать debug=True, то он заменит все неразрывные пробелы на символ подчеркивания, это может быть полезным для отладки:
ru_typus('(c) me', debug=True) '_me'
Демо
Важно: демо крутится на очень простой виртуалке и предназначено для демонстрации возможностей.
Я ничего никуда не сохраню (честно), исходный код сайта вы найдете у меня на гитхабе.
Установка и использование
pip install -e git://github.com/byashimov/typus.git#egg=typus
Далее:
from typus import en_typus, ru_typus en_typus('"Beautiful is better than ugly." (c) Tim Peters.', debug=True) '“Beautiful is_better than ugly.” _Tim Peters.' # _ for nbsp ru_typus('"Красивое луч��е, чем уродливое." (с) Тим Петерс.') '«Красивое лучше, чем уродливое.» Тим Петерс.' # cyrillic 'с' in '(с)'
Документация
Эту статью можно считать таковой, пока я не сделаю корявый перевод на английский.
Совместимость
Name Stmts Miss Cover ----------------------------------------- typus/__init__.py 8 0 100% typus/chars.py 18 0 100% typus/core.py 24 0 100% typus/mixins.py 77 0 100% typus/processors.py 99 0 100% typus/utils.py 30 0 100% ----------------------------------------- TOTAL 256 0 100% ________________ summary ________________ py25: commands succeeded py26: commands succeeded py27: commands succeeded py33: commands succeeded py34: commands succeeded py35: commands succeeded congratulations :)
Travis-CI, которым я пользуюсь, не поддерживает 2.5, а вручную я проверять не всегда тружусь, так что если вы еще им пользуетесь (соболезную), запустите тесты после установки.
Планы и какие-то идеи
- Я не планирую вносить в типограф подчеркивание ссылок или расстановку html-тегов. Этим должен занимать процессор текстов (markdown, retext и т. д.). К тому же, у всех свои кейсы.
- Я также не хотел бы, чтобы типограф исправлял ошибки в тексте, даже если это ничего не стоит.
- Почти все типографы конвертируют небезопасные символы, такие как
&, в html-сущности. На данный момент мне не ясно зачем это делать: браузеры, поисковики и парсеры справляются играючи с таким текстом, а гонять cpu просто так и делать код нечитаемым мне совсем не хочется. Буду рад конкретному примеру. - Вероятно,
ru_typusсправится с украинскими и белорусскими текстами (а возможно и с другими), если так, я внесу это в описание проекта.
Вроде все.
P. S. Какой-то ад с подсветкой инлайн кода на хабре.
