Поддержка текста Юникода (интернационализированного)

podderzhka teksta junikoda internacionalizirovannogo Примеры законченных программ с графическим интерфейсом

Наконец, из-за того, что теперь Python 3.X полностью поддерживает текст Юникода, редактор PyEdit также обеспечивает эту поддержку — он позволяет открывать, сохранять, просматривать, редактировать и отыскивать в дереве каталогов любой текст, в любой кодировке и с любыми наборами символов. Эта поддержка находит множество отражений в пользовательском интерфейсе PyMailGUI:

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

     При сохранении нового файла запрашивается имя кодировки, если она не указана в настройках’

     При отображении и редактировании используется поддержка Юникода, реализованная в инструментах создания графических интерфейсов’

     Операция поиска в дереве каталогов позволяет явно указывать кодировку, которая будет применяться ко всем файлам в дереве, и пропускает файлы, декодировать которые не удалось, как было описано выше’

Благодаря этому обеспечивается поддержка интернационализированного текста, кодировка которого может отличаться от кодировки по умолчанию, используемой на текущей платформе. Это, в частности, удобно для просмотра текстовых файлов, полученных из Интернета, по электронной почте или через FTP. Приложение PyMailGUI из главы 14, например, использует встроенный объект PyEdit для отображения текста вложений различного происхождения и в различных кодировках. Поддержка Юникода в операции поиска по файлам была описана выше — остальные аспекты этой модели, по сути, сводятся к операциям открытия и сохранения файлов, как описывается в следующем разделе. Файлы с текстом Юникода и модель отображения их содержимого. Поскольку строки в Python 3.X всегда интерпретируются как последовательности кодовых пунктов Юникода, поддержка Юникода в действительности означает поддержку различных кодировок при чтении и записи в текстовые файлы. Напомню, что текст может сохраняться в файлах в различных кодировках, — данные декодируются при чтении и кодируются при записи с применением этих кодировок. Если текст не всегда сохраняется в файлах с использованием кодировки по умолчанию для данной платформы, то для таких случаев нам необходимо знать, какую кодировку использовать при чтении и записи.

Чтобы обеспечить такую поддержку, редактор PyEdit использует подходы, подробно описанные в главе 9. Мы не будем повторно обсуждать их здесь, тем не менее в двух словах отмечу, что виджет Text принимает содержимое в виде строки типа str или bytes и всегда возвращает его как строку str. Редактор PyEdit отображает этот интерфейс на интерфейс объектов файлов языка Python следующим образом:

Входные файлы (открытие)

Чтобы декодировать байты из файла в строки, в общем случае требуется знать название кодировки, совместимой с данными в файле. Если кодировка окажется несовместимой, операция декодирования потерпит неудачу (например, при попытке декодировать 8-битовые данные с использованием кодировки ASCII). В некоторых случаях кодировка открываемого текстового файла может оказаться неизвестной.

Чтобы при загрузке содержимого входных файлов прочитать данные в виде строк str, редактор PyEdit сначала пытается открывать их в текстовом режиме, применяя кодировки, полученные из разных источников: из аргумента метода, когда кодировка известна заранее (например, из заголовков вложений в сообщениях электронной почты или из исходных файлов, открываемых демонстрационными примерами), из диалога, запрашивающего кодировку у пользователя, из модуля с настройками и из параметров по умолчанию текущей платформы. При выводе диалога, запрашивающего кодировку при открытии файла, поле ввода предварительно заполняется вариантом из файла с настройками, который считается значением по умолчанию.

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

Обработка текста

При обращении к виджету Text он возвращает свое содержимое в виде строки str, независимо от того, в каком виде, str или bytes, был вставлен текст. Вследствие этого вся обработка текстового содержимого производится с применением методов строк str Юникода.

Выходные файлы (сохранение)

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

Для сохранения текста в файл редактор PyEdit открывает выходной файл в текстовом режиме, чтобы обеспечить отображение символов конца строки и кодирование содержимого строки str Юникода. Имя кодировки извлекается из одного из источников — это может быть кодировка, использовавшаяся при открытии или первоначальном сохранении файла (если была указана), или кодировка, полученная из диалога с пользователем, из модуля с настройками или из параметров по умолчанию текущей платформы. В отличие от операции открытия, когда операция сохранения выводит диалог запроса имени кодировки, поле ввода заполняется именем известной кодировки, если она была определена прежде, в противном случае берется вариант из файла с настройками, как и в случае с операцией открытия.

Диалоги ввода кодировки, вызываемые операциями открытия и сохранения файлов, — это лишь одно из воплощений описанных правил в графическом интерфейсе; другие варианты определяются в модуле с настройками. Поскольку заранее невозможно предугадать все возможные случаи использования, в редакторе PyEdit применяется либеральный подход: он поддерживает все мыслимые режимы и обеспечивает пользователям возможность влиять на определение кодировок с помощью определения настроек в их собственном модуле textConfig. Он пытается применить одну кодировку за другой из разных источников, если это разрешено в модуле textConfig, пока не будет найдена кодировка, дающая положительные результаты. Тем самым достигается максимальная маневренность перед лицом переменчивого мира Юникода.

Например, согласно параметрам в файле с настройками операция сохранения повторно использует кодировку, которая применялась при открытии файла или при первой операции сохранения, если она известна. Для новых файлов (созданных выбором пункта New в меню или вставкой текста вручную) и для файлов, открытых в двоичном режиме, кодировка остается неизвестной до момента сохранения, но для файлов, которые удалось открыть в текстовом режиме, она известна. Кроме того, с помощью параметров в файле с настройками мы можем определить необходимость запрашивать кодировку у пользователя при выполнении операции Save As (и, возможно, Save), потому что у него могут быть свои предпочтения при создании новых файлов. Мы также можем запрашивать кодировку при открытии существующих файлов, потому что для этого необходимо знать его текущую кодировку. В некоторых случаях (например, для файлов, полученных из Интернета) пользователь может не знать ее, но в других случаях он может предпочесть указать кодировку явно. Вместо того чтобы выбирать тот или иной порядок действий в таких ситуациях, мы просто опираемся на пользовательские настройки.

На практике все это относится только к клиентам PyEdit, которые запрашивают начальную загрузку файлов или позволяют открывать и сохранять файлы с помощью графического интерфейса. Поскольку содержимое может вставляться как строка типа str или bytes, клиенты всегда имеют возможность читать входные файлы самостоятельно, до создания объекта текстового редактора, и вставлять в него текст вручную. Кроме того, клиенты могут получать содержимое вручную и сохранять его любым предпочитаемым способом. Такое выполнение операций вручную может оказаться полезным, если в каком-то контексте методика, реализованная в редакторе PyEdit, окажется нежелательной. Поскольку виджет Text всегда возвращает содержимое в виде строки str, остальной части этой программы безразлично, строка какого типа была в него вставлена.

Имейте в виду, что описанная методика по-прежнему зависит от поддержки Юникода и от ограничений, заложенных в библиотеке Tk, а также от интерфейса tkinter к ней. Редактор PyEdit позволяет загружать и сохранять текст в любой кодировке, но он не может гарантировать, что библиотека графического интерфейса сможет отобразить такой текст. То есть даже если мы совершенно корректно обрабатываем текст Юникода на стороне Python, мы все равно остаемся во власти других слоев программного обеспечения, обсуждение которых выходит далеко за рамки этой книги. Библиотека Tk достаточно надежно работает с самыми разными наборами символов, если ей передавать уже декодированные строки str Юникода (смотрите, например, описание поддержки интернационализации в PyMailGUI в главе 14), но ситуации в конкретных случаях могут сильно различаться.

Порядок выбора кодировки и возможные варианты. Имейте также в виду, что политика редактора PyEdit в отношении Юникода отражает предпочтения единственного текущего пользователя и не проверялась на универсальность и эргономику — будучи книжным примером, редактор не использует встроенную среду тестирования, как это свойственно проектам с открытыми исходными текстами. Неплохие результаты можно было бы получать, используя другие схемы и порядки следования источников, и совершенно невозможно предугадать предпочтения каждого пользователя в каждом конкретном случае. Например:

     Непонятно, следует ли сначала запрашивать кодировку у пользователя, а потом пытаться использовать кодировку, указанную в файле с настройками, или наоборот.

     Возможно также, что мы всегда должны спрашивать кодировку у пользователя, полагаясь в основном на это, независимо от параметров настройки.

     При сохранении мы могли бы также попробовать самостоятельно определить кодировку для применения к строке str (например, попробовать применить UTF-8, Latin-1 или другую распространенную кодировку), но наши предположения могут не совпадать с тем, что имел в виду пользователь.

     Весьма вероятно, что пользователь пожелает сохранить файл в той же кодировке, которая применялась при открытии файла или при сохранении в первый раз. Редактор PyEdit предоставляет поддержку этого варианта, в противном случае графический интерфейс запрашивал бы кодировку для данного файла более чем один раз. Однако, поскольку некоторым пользователям может потребоваться повторно использовать операцию Save, чтобы сохранить тот же файл в другой кодировке, то предусмотрена возможность отключения этого варианта в модуле с настройками. На первый взгляд, для этой цели было бы лучше использовать операцию Save As, однако следующий пункт объясняет, почему это не всегда так.

     Точно так же неочевидно, должна ли операция Save As повторно использовать кодировку, которая применялась при открытии или при сохранении файла в первый раз, или она должна запрашивать новую кодировку — действительно ли при этом сохраняется совершенно новый файл или только копия предыдущего содержимого с установленной кодировкой, но под новым именем? Из-за такой неоднозначности мы даем возможность запретить использование установленной кодировки в операции Save As или в обеих операциях, Save и Save As, в модуле с настройками. По умолчанию использование известной кодировки разрешено только для операции Save и запрещено для Save As. В любом случае, операции сохранения выводят диалоги, запрашивающие имя кодировки, в которых поле ввода заполнено известной кодировкой.

     Порядок выбора вариантов вообще выглядит весьма спорным. Например, возможно, операция Save As должна использовать известную кодировку, если настройки запрещают запрашивать ее у пользователя, — в данной реализации, если настройки запрещают использовать известную кодировку и запрашивать ее у пользователя, эта операция будет определять кодировку из файла с настройками или использовать системную кодировку по умолчанию (например, UTF-8), что может оказаться не самым лучшим решением при сохранении составных частей сообщений электронной почты, кодировка которых уже известна.

И так далее. Поскольку такой пользовательский интерфейс обеспечивает широчайший выбор вариантов, в целях иллюстрации в этой книге реализованы общий и частично эвристический алгоритмы поддержки каждого из возможных вариантов, и в качестве опоры при выборе используются настройки пользователя. Однако на практике такая гибкость может оказаться совершенно излишней — большинству пользователей наверняка будет достаточно поддержки какого-то одного алгоритма из числа поддерживаемых здесь.

Кроме того, вероятно, было бы удобнее, если бы алгоритмом выбора кодировки можно было управлять непосредственно в графическом интерфейсе, вместо того чтобы вручную определять его в модуле с настройками. Например, возможно, каждая операция — Open, Save и Save As — должна позволять выбирать кодировку и по умолчанию использовать последнюю известную кодировку, если таковая определена. Реализация этой возможности в виде раскрывающихся списков с именами кодировок или полей ввода в диалогах Save и Open позволила бы отказаться от лишних диалогов и достичь практически той же гибкости.

В текущей реализации редактора PyEdit имеется возможность определить в файле с настройками необходимость запрашивать кодировку у пользователя для обеих операций, открытия и сохранения, что дает практически тот же эффект, по крайней мере в тех ситуациях, с которыми я сталкивался до настоящего момента, и, возможно, является лучшим решением для большинства контекстов.

Таким образом, по умолчанию:

     Операция Open использует переданную ей кодировку, если она была указана, или запрашивает имя кодировки у пользователя

     Операция Save повторно использует известную кодировку, если она была определена ранее, а при сохранении новых файлов запрашивает ее у пользователя

     Операция Save As всегда запрашивает имя кодировки у пользователя, как при сохранении нового файла

     Операция Grep позволяет вводить кодировку в диалоге определения параметров поиска и применяет ее при поиске во всех файлах, имеющихся в дереве каталогов

С другой стороны, поскольку умолчаний, определяемых платформой, будет вполне достаточно для работы без лишних сложностей взаимодействия с графическим интерфейсом, по крайней мере, для подавляющего числа пользователей, с помощью параметров в модуле textConfig можно предотвратить вывод диалога запроса кодировки и вернуться к использованию кодировки, указанной явно или определяемой платформой по умолчанию. В конечном счете, определение наиболее удачного алгоритма выбора кодировки требует анализа предпочтений широкого круга пользователей, а не предположений единственного разработчика. Как всегда, вы свободно можете адаптировать этот алгоритм под свои потребности.

В подкаталоге test в дереве примеров вы найдете несколько текстовых файлов в различных кодировках, с которыми вы можете экспериментировать при изменении алгоритмов выбора кодировки в модуле textConfig для операций открытия и сохранения файлов. Этот каталог содержит файлы, изображенные на рис. 11.5 и 11.6, в которых используются национальные наборы символов и сохраненные в различных кодировках. Например, файл emailpartkoi8-r содержит текст на русском языке, сохраненный в кодировке koi8-r, а файл emailpartkoi8-rutf8 содержит тот же текст, сохраненный в кодировке UTF-8, — последний можно открыть в программе Блокнот (Notepad) в Windows, но первый будет корректно отображен только при передаче PyEdit явно указанной кодировки.

Еще лучше, сохраните сами один и тот же файл в нескольких кодировках, жестко определяя кодировку в модуле textConfig или указывая разные кодировки при сохранении, — благодаря широкомасштабной поддержке Юникода в Python 3.X, редактор PyEdit позволяет сохранять и загружать файлы практически в любой кодировке.

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

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