Другие проблемы двоичного режима

drugie problemy dvoichnogo rezhima Экскурсия по tkinter, часть 2

Даже в ситуациях, когда достаточно использовать файлы, открытые в двоичном режиме, обойти проблемы с кодировками оказывается сложнее, чем можно было бы подумать. При записи в двоичном режиме нам всегда придется проявлять осторожность, чтобы прочитанные данные позднее были корректно записаны в файл, при чтении в двоичном режиме строки в Windows будут завершаться последовательностью символов \r\n и было бы нежелательно, чтобы при записи в текстовом режиме они превращались в последовательности \r\r\n. Кроме того, между строками типа str и bytes в tkinter существует еще одно отличие. Строки str, прочитанные из файла в текстовом режиме, выводятся в графическом интерфейсе в ожидаемом виде, и в Windows символы конца строки отображаются должным образом:

C:\…\PP4E\Gui\Tour> python

>  >> from tkinter import *

>  >> T = Text() # str в текстовом режиме

>  >> T.insert(‘1.0’, open(‘jack.txt’).read()) # кодировка по умолчанию

>  >> T.pack() # нормально отображается в GUI

>  >> T.get(‘1.0’, ‘end’)[:75]

‘000) All work and no play makes Jack a dull boy.\n001) All work and no pla’

Однако если передать в графический интерфейс строку bytes, прочитанную из файла в двоичном режиме, в Windows она будет выглядеть на экране довольно странно в конце каждой строки текста появится лишний пробел, соответствующий символу \r, который не отсекается при чтении из файлов в двоичном режиме:

C:\…\PP4E\Gui\Tour> python

>  >> from tkinter import *

>  >> T = Text() # bytes в двоичном режиме

>  >> T.insert(‘1.0’, open(‘jack.txt’, ‘rb’).read()) # без декодирования

>  >> T.pack() # появились пробелы в конце

>  >> T.get(‘1.0’, ‘end’)[:75] # строк!

‘000) All work and no play makes Jack a dull boy.\r\n001) All work and no pl’

При использовании строк bytes, чтобы обеспечить отображение произвольного текста в ожидаемом виде, нам дополнительно придется вручную удалять символы \r в концах строк. Вследствие этого предполагается, что комбинация \r\n не имеет какого-то специального значения в схеме кодирования текста, хотя, если эта последовательность в данных не будет означать конец строки, такие данные с большой долей вероятности будут вызывать другие проблемы при отображении. В следующем фрагменте реализовано удаление лишних пробелов в концах строк входной файл открывается в двоичном режиме, и при чтении недекодированных байтов вручную удаляются символы \r:

C:\\PP4E\Gui\Tour> python

>  >> from tkinter import * # используется тип bytes, удаляются символы \r

>  >> T = Text()

>  >> data = open(‘jack.txt’, ‘rb’).read()

>>> data = data.replace(b’\r\n’, b’\n’)

>>> T.insert(‘1.0’, data)

>>> T.pack()

>>> T.get(‘1.0’, ‘end’)[:75]

‘000) All work and no play makes Jack a dull boy.\n001) All work and no pla’

Чтобы позднее сохранить это содержимое, можно либо добавить символы \r, при выполнении в Windows, вручную выполнить кодирование в тип bytes и сохранить данные в двоичном режиме; либо открыть файл в текстовом режиме, чтобы объект файла сам добавил символы \r, если это необходимо, выполнил кодирование и записал содержимое строки str. Второй путь, вероятно, более простой, так как он не требует беспокоиться о различиях между платформами.

Однако в любом случае мы вновь оказываемся лицом к лицу с проблемой кодирования — мы можем либо положиться на кодировку по умолчанию для текущей платформы, либо получить имя кодировки из пользовательского интерфейса. В следующем фрагменте, например, объект текстового файла сам преобразует символы конца строки и применяет кодировку по умолчанию для текущей платформы. Если бы было необходимо обеспечить поддержку произвольного текста Юникода или работоспособность сценария на платформах, где кодировка по умолчанию не соответствует отображаемым символам, мы могли бы передавать имя кодировки явно (операция извлечения среза, используемая здесь, имеет тот же эффект, что и применение спецификатора позиции «end-1c» в библиотеке Tk):

…продолжение предыдущего сеанса…

>>> content = T.get(‘1.0’, ‘end’)[:-1] # отбросит \n в конце

>>> open(‘copyjack.txt’, ‘w’).write(content) # кодировка по умолчанию

12500 # текстовый режи’ BWin добавит \n

>>> "Z

C:\…\PP4E\Gui\Tour> fc jack.txt copyjack.txt

Comparing files jack.txt and COPYJACK.TXT FC: no differences encountered

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий