Шаг 43.
Python: сборник рецептов.
Строки и текст. Выполнение текстовых операций над байтовыми строками

    На этом шаге мы рассмотрим работу с байтовыми строками.

Задача

    Вы хотите выполнить стандартные текстовые операции (срезание символов, поиск, замену) над строками байтов.

Решение

    Байтовые строки поддерживают большую часть тех же встроенных операций, что и текстовые строки. Например:

>>> data = b'Hello World'
>>> data[0:5]
b'Hello'
>>> data.startswith(b'Hello')
True
>>> data.split()
[b'Hello', b'World']
>>> data.replace(b'Hello', b'Hello Cruel')
b'Hello Cruel World'
>>> 

    Такие операции можно проделать и над байтовыми массивами:

>>> data = bytearray(b'Hello World')
>>> data[0:5]
bytearray(b'Hello')
>>> data.startswith(b'Hello')
True
>>> data.split()
[bytearray(b'Hello'), bytearray(b'World')]
>>> data.replace(b'Hello', b'Hello Cruel')
bytearray(b'Hello Cruel World')
>>> 

    Вы можете просто применить к байтовым строкам поиск совпадений с помощью регулярных выражений, но сами шаблоны должны быть определены как байты. Например:

>>> data = b'FOO:BAR,SPAM'
>>> import re
>>> re.split('[:,]',data)
Traceback (most recent call last):
  .   .   .   .
TypeError: cannot use a string pattern on a bytes-like object
>>> re.split(b'[:,]',data)  # Обратите внимание: шаблон в байтах
[b'FOO', b'BAR', b'SPAM']
>>> 


Обсуждение

    Практически все доступные для текстовых строк операции будут работать и на байтовых строках. Однако есть несколько заметных отличий, о которых нужно знать. Во-первых, при индексировании байтовых строк мы получаем целые числа, а не символы. Например:

>>> a = 'Hello World' # Текстовая строка
>>> a[0]
'H'
>>> a[1]
'e'
>>> b = b'Hello World' # Байтовая строка
>>> b[0]
72
>>> b[1]
101
>>> 

    Эта разница в семантике может влиять на программы, которые пытаются обработать байтовые данные так же, как и текстовые.

    Во-вторых, байтовые строки не предоставляют красивые строковые представления и не выводятся в симпатичном виде, если сначала не проведено декодирование в текстовую строку. Например:

>>> s = b'Hello World'
>>> print(s)
b'Hello World'
>>> print(s.decode('ascii'))
Hello World
>>> 

    Строковая операция format() недоступна для байтовых строк.

>>> b'%10s %10d %10.2f' % (b'ACME', 100, 490.1)
b'      ACME        100     490.10'
>>> b'{} {} {}'.format(b'ACME', 100, 490.1)
Traceback (most recent call last):
  .   .   .   .
AttributeError: 'bytes' object has no attribute 'format'
>>> 

    Если вы хотите применить какое-то форматирование к байтовой строке, это должно быть проделано с помощью обычных текстовых строк и последующего кодирования. Например:

>>> '{:10s} {:10d} {:10.2f}'.format('ACME', 100, 490.1).encode('ascii')
b'ACME              100     490.10'
>>>

    И наконец, вы должны знать, что использование байтовых строк может изменить семантику некоторых операций, особенно тех, что относятся к файловой системе. Например, если вы предоставляете имя файла закодированным в байтовую строку, а не в текстовую, это обычно отключает кодирование и декодирование имени файла. Например:

>>> # Запишем имя файла в UTF-8
>>> with open('jalape\xf1o.txt', 'w') as f:
	f.write('spicy')

	
5
>>> # Получим содержимое каталога
>>> import os
>>> os.listdir('.') # Текстовая строка (имена декодированы)
[..., 'jalapeño.txt', ...]
>>> os.listdir(b'.') # Байтовая строка (имена остались байтами)
[..., b'jalapen\xcc\x83o.txt', ...]
>>>

    Посмотрите, как в последней части этого примера передача имени каталога в виде байтовой строки вызывает возврат имен файлов в виде недекодированных байтов.

    Имя файла, показанное в списке содержимого каталога, содержит "сырую" кодировку UTF-8.

    Некоторые программисты могут склоняться к использованию байтовых строк в качестве альтернативы текстовым из-за возможного выигрыша в производительности. Да, операции над байтами могут быть немного более эффективными, чем работа с текстом (из-за расходов на Unicode), однако такой подход приводит к грязному и неидиоматическому коду. Вы будете часто сталкиваться с тем, что байтовые строки не очень хорошо сочетаются с другими частями Python, и закончите тем, что будете вручную выполнять всевозможные операции кодирования-декодирования, чтобы все работало. Так что если вы работаете с текстом, используйте обычные текстовые строки, а не байтовые.

    Со следующего шага мы начнем рассматривать работу с числами, датами и временем.




Предыдущий шаг Содержание Следующий шаг