Кроме того, пакет email предоставляет также поддержку кодирования и декодирования самих заголовков сообщений (таких как «From», «Sub- ject») в соответствии со стандартами электронной почты, когда они не являются простым текстом. Такие заголовки иногда называют ин терна цио на ли зиро ван ны ми (или i18n) заголовками, потому что они поддерживают включение в почтовые сообщения символов, не входящих в набор ASCII. Этот термин иногда используется также для обозначения кодированного текста содержимого в сообщениях. Однако, в отличие от заголовков сообщений, при создании содержимого сообщений кодированию подвергается не только текст с интернациональными символами Юникода, но и действительно двоичные данные, такие как изображения (как будет показано в следующем разделе).
Как и информационное наполнение, интернационализированные заголовки в почтовых сообщениях кодируются особым образом и могут также кодироваться с применением кодировок Юникода. Например, следующий фрагмент демонстрирует, как можно декодировать заголовок темы сообщения, возможно, являющегося спамом, которое только что появилось в моем почтовом ящике. Преамбула =?UTF-8?Q? в заголовке свидетельствует, что данные, следующие за ней, являются текстом Юникода, закодированным с помощью кодировки UTF-8, который дополнительно был преобразован в MIME-формат quoted-printable для передачи по электронной почте (в отличие от примеров содержимого, приводившихся в предыдущем разделе, кодировка которых объявляется в отдельных заголовках, сами заголовки могут встраивать свои схемы кодирования Юникода и MIME прямо в свое содержимое, как в данном случае):
> >> rawheader = ‘=?UTF-8?Q?Introducing=20Top=20Values=3A=20A=20Special=20Selec tion=20of=20Great=20Money=20Savers?=’
> >> from email.header import decode_header # выполнить декодирование
> >> decode_header(rawheader) # email+MIME
[(b’Introducing Top Values: A Special Selection of Great Money Savers’, ‘utf-8’)]
> >> bin, enc = decode_header(rawheader)[0] # декодировать в Юникод
> >> bin, enc
(b’Introducing Top Values: A Special Selection of Great Money Savers’, ‘utf-8’)
> >> bin.decode(enc)
‘Introducing Top Values: A Special Selection of Great Money Savers’
Важно отметить, что пакет email может возвращать несколько частей, если в заголовке имеется несколько подстрок, каждую из которых требуется декодировать отдельно, и затем объединять их, чтобы получить полный текст заголовка. Обратите также внимание, что в версии 3.1 этот пакет возвращает строку bytes, если в заголовке имеется хотя бы одна закодированная подстрока (или весь заголовок), но возвращает строку str, если заголовок не был закодирован, а некодированные подстроки возвращаются в виде строк bytes при применении кодировки «raw-unicode-escape», которую удобно использовать для преобразования строки str в строку bytes, когда никакое кодирование не применяется:
> >> from email.header import decode_header
> >> S1 = ‘Man where did you get that assistant?’
> >> S2 = ‘=?utf-8?q?Man_where_did_you_get_that_assistant=3F?=’
> >> S3 = ‘Man where did you get that =?UTF-8?Q?assistant=3F?=’
> str: не требуется вызывать decode()
> >> decode_header(S1)
[(‘Man where did you get that assistant?’, None)]
> bytes: требуется вызвать decode()
> >> decode_header(S2)
[(b’Man where did you get that assistant?’, ‘utf-8’)]
> bytes: требуется вызвать decode(), пакет применит
> кодировку raw-unicode-escape
> >> decode_header(S3)
[(b’Man where did you get that’, None), (b’assistant?’, ‘utf-8’)]
> объединить декодированные части, если их несколько
> >> parts = decode_header(S3)
> >> ‘ ‘.join(abytes.decode(‘raw-unicode-escape’ if enc == None else enc)
… for (abytes, enc) in parts)
‘Man where did you get that assistant?’
К логике, подобной использованной здесь на последнем шаге, мы будем обращаться в пакете mailtools и далее, но также будем оставлять подстроки str нетронутыми, не пытаясь их декодировать.
Самые последние новости: В середине 2010 года, когда я пишу эти строки, кажется вполне возможным, что такое неполиморфическое и, честно признаться, непитоническое поведение прикладного интерфейса, смешивающего разные типы данных, изменится в будущих версиях Python. В ответ на тираду, посланную в список рассылки разработчиков Python автором книги, с работами которого вы, возможно, знакомы, разгорелось жаркое обсуждение этой темы. Среди прочих родилась идея создать тип, подобный bytes, который явно будет нести в себе название кодировки — в некоторых ситуациях такой тип позволил бы организовать обработку текстовых данных более универсальным образом. Заранее невозможно предсказать, во что выльются такие идеи, но приятно видеть, когда они активно обсуждаются. Следите за информацией на веб-сайте книги, где будет сообщаться об изменениях в API библиотеки Python 3.X и обо всем, что касается поддержки Юникода.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011