т. (383) 381-86-26

Блог о создании вебсайтов

 

Python textwrap. Модуль для работы с текстом

 

Эта статья часть серии переводов PyMOTW3

Модуль предоставляет функции для форматирования текста с помощью контроля разбиения строк. Используется для обработки текста там, где требуется pretty-printing и предоставляет программные инструменты, похоже на известные функции текстовых редакторов: wrap, fill и т.д.

Данные для примеров

Все примеры ниже используют модуль textwrap_example.py, который содержит следующий текст:


#textwrap_example.py

sample_text = '''
    The textwrap module can be used to format text for output in
    situations where pretty-printing is desired.  It offers
    programmatic functionality similar to the paragraph wrapping
    or filling features found in many text editors.
    '''

Заполнение параграфов

Функция fill() принимает текст в качестве аргумента и возвращает форматированный текст.


textwrap_fill.py

import textwrap
from textwrap_example import sample_text

print(textwrap.fill(sample_text, width=50))

Результаты не совсем такие какие хотелось бы. Текст теперь выровнен по левому краю, но был сохранён отступ в первой строке, пробелы же в начале каждой последующей строки теперь часть параграфа.


$ python3 textwrap_fill.py

     The textwrap module can be used to format
text for output in     situations where pretty-
printing is desired.  It offers     programmatic
functionality similar to the paragraph wrapping
or filling features found in many text editors.

Очистка существующего форматирования

Предыдущий пример содержал в результате смесь из табуляций и пробелов, так что форматирование на самом деле было выполнено достаточно коряво. С помощью dedent() можно убрать в нашем примере пробелы в начале каждой строки. По сути текст будет смещен на одну позицию влево.


textwrap_dedent.py

import textwrap
from textwrap_example import sample_text

dedented_text = textwrap.dedent(sample_text)
print('Dedented:')
print(dedented_text)

$ python3 textwrap_dedent.py

Dedented:

The textwrap module can be used to format text for output in
situations where pretty-printing is desired.  It offers
programmatic functionality similar to the paragraph wrapping
or filling features found in many text editors.

Так как dedent() является противоположностью indent(), то в результате мы получим текст, в котором будет вырезан пробел в начале каждой строки. При этом, если какая-либо строка была сдвинута больше, чем другая, то их положение по отношению друг к другу сохранится.


>>> print(s)

    a
      b
       c
>>> print(t.dedent(s))

a
  b
   c
>>> s = '\n    a\n  b\n       c'
>>> print(t.dedent(s))

  a
b
     c
>>> s = '\n    a\n  b\n       c'
>>> print(s)

    a
  b
       c
>>> print(t.dedent(s))

  a
b
     c
     

Т.е. исходный текст:

␣Line one.
␣␣␣Line two.
␣Line three.

Превращается в:

Line one.
␣␣Line two.
Line three.

Комбинируем fill() & dedent()

Если после dedent пропустить текст через fill, то можно задавать его ширину


# textwrap_fill_width.py

import textwrap
from textwrap_example import sample_text

dedented_text = textwrap.dedent(sample_text).strip()
for width in [45, 60]:
    print('{} Columns:\n'.format(width))
    print(textwrap.fill(dedented_text, width=width))
    print()
    

В результате получим текст требуемой ширины:


$ python3 textwrap_fill_width.py

45 Columns:

The textwrap module can be used to format
text for output in situations where pretty-
printing is desired.  It offers programmatic
functionality similar to the paragraph
wrapping or filling features found in many
text editors.

60 Columns:

The textwrap module can be used to format text for output in
situations where pretty-printing is desired.  It offers
programmatic functionality similar to the paragraph wrapping
or filling features found in many text editors.

Создание отступов

indent() можно использовать для того, чтобы давать префиксы строкам. Например, можно добавить к каждой строке префикс '>', как-будто это цитата в email:


#textwrap_indent.py

import textwrap
from textwrap_example import sample_text

dedented_text = textwrap.dedent(sample_text)
wrapped = textwrap.fill(dedented_text, width=50)
wrapped += '\n\nSecond paragraph after a blank line.'
final = textwrap.indent(wrapped, '> ')

print('Quoted block:\n')
print(final)

В результате получится что-то подобное вот этому:

$ python3 textwrap_indent.py

Quoted block:

>  The textwrap module can be used to format text
> for output in situations where pretty-printing is
> desired.  It offers programmatic functionality
> similar to the paragraph wrapping or filling
> features found in many text editors.

> Second paragraph after a blank line.

Но это ещё не всё. indent предоставляет нам возможность контролировать какая строка получит префикс, а какая нет. Для этого можно передать callable объект, который должен возвращать True или False. Как ты уже догадался, indent добавит префикс к тем строкам, при обработке которых предикат выдал True. Пример


textwrap_indent_predicate.py

import textwrap
from textwrap_example import sample_text


def should_indent(line):
    print('Indent {!r}?'.format(line))
    return len(line.strip()) % 2 == 0


dedented_text = textwrap.dedent(sample_text)
wrapped = textwrap.fill(dedented_text, width=50)
final = textwrap.indent(wrapped, 'EVEN ',
                        predicate=should_indent)

print('\nQuoted block:\n')
print(final)

Этот пример добавляет EVEN в качестве предиката к строке, в которой четное число символов. В результате получим вот что:

$ python3 textwrap_indent_predicate.py

Indent ' The textwrap module can be used to format text\n'?
Indent 'for output in situations where pretty-printing is\n'?
Indent 'desired.  It offers programmatic functionality\n'?
Indent 'similar to the paragraph wrapping or filling\n'?
Indent 'features found in many text editors.'?

Quoted block:

EVEN  The textwrap module can be used to format text
for output in situations where pretty-printing is
EVEN desired.  It offers programmatic functionality
EVEN similar to the paragraph wrapping or filling
EVEN features found in many text editors.

Отступ первой строки

Оказывается, можно также независимо контролировать отступ первой строки:


# textwrap_hanging_indent.py

import textwrap
from textwrap_example import sample_text

dedented_text = textwrap.dedent(sample_text).strip()
print(textwrap.fill(dedented_text,
                    initial_indent='',
                    subsequent_indent=' ' * 4,
                    width=50,
                    ))
                    

Таким образом можно сделать нулевым первый отступ, а последующие строки сместить:

$ python3 textwrap_hanging_indent.py

The textwrap module can be used to format text for
    output in situations where pretty-printing is
    desired.  It offers programmatic functionality
    similar to the paragraph wrapping or filling
    features found in many text editors.
    

Префиксы, как ты уже понял могут быть не только пробелами, но и любыми символами. Таким образом с помощью этого трюка можно красиво генерировать и форматировать списки.

Обрезка длинного текста

Модуль textwrap предоставляет функцию для усечения текста — shorten() . Это удобно, когда требуется сгенерировать небольшое резюме для более длинного текста из первых его строк. Все существующие в тексте серии пробелов, табуляции, переводы строк будут заменены на одинарный пробел и текст будет обрезан до длины меньшей или равной заданной в параметре функции в пределах последнего слова (чтобы не было обрезанных слов)


# textwrap_shorten.py

import textwrap
from textwrap_example import sample_text

dedented_text = textwrap.dedent(sample_text)
original = textwrap.fill(dedented_text, width=50)

print('Original:\n')
print(original)

shortened = textwrap.shorten(original, 100)
shortened_wrapped = textwrap.fill(shortened, width=50)

print('\nShortened:\n')
print(shortened_wrapped)

Если был обрезан не пустой текст в виде пробелов, табов и т.д., тогда в конец усеченного текста будет добавлен placeholder "[...]". Его значение также можно задать через аргумент функции shorten()

$ python3 textwrap_shorten.py

Original:

 The textwrap module can be used to format text
for output in situations where pretty-printing is
desired.  It offers programmatic functionality
similar to the paragraph wrapping or filling
features found in many text editors.

Shortened:

The textwrap module can be used to format text for
output in situations where pretty-printing [...]

Подпишитесь на рассылку, будет интересно!