Попытка адресовать эту проблему, я пытаюсь обернуть голову вокруг различных функций стандартной библиотеки Python, направленных на поддержку RFC 2231. Основная цель этого RFC представляется в три раза: позволяет кодирование без ASCII в параметрах заголовка, отмечая язык заданного значения и позволяя параметрам заголовка охватывать несколько строк. Библиотека email.util
предоставляет несколько функций для решения различных аспектов этого. Насколько я могу судить, они работают следующим образом:
decode_rfc2231
только разделяет значение такого параметра на его части, например:
>>> email.utils.decode_rfc2231("utf-8''T%C3%A4st.txt")
['utf-8', '', 'T%C3%A4st.txt']
decode_params
заботится об обнаружении параметров, закодированных RFC2231. Он собирает части, которые принадлежат друг другу, а также декодирует строку с кодировкой url в байтовую последовательность. Эта последовательность байтов, однако, затем кодируется как latin1. И все значения заключены в кавычки. Кроме того, существует некоторая специальная обработка для первого аргумента, которая по-прежнему должна быть кортежем из двух элементов, но эти два передаются без результата.
>>> email.utils.decode_params([
... (1,2),
... ("foo","bar"),
... ("name*","utf-8''T%C3%A4st.txt"),
... ("baz*0","two"),("baz*1","-part")])
[(1, 2), ('foo', '"bar"'), ('baz', '"two-part"'), ('name', ('utf-8', '', '"Täst.txt"'))]
collapse_rfc2231_value
можно использовать для преобразования этой тройки кодировки, языка и последовательности байтов в правильную строку юникода. Однако меня смущает тот факт, что если вход был такой тройной, то кавычки будут перенесены на выход. Если, с другой стороны, вход был одиночной кавычкой, то эти кавычки будут удалены.
>>> [(k, email.utils.collapse_rfc2231_value(v)) for k, v in
... email.utils.decode_params([
... (1,2),
... ("foo","bar"),
... ("name*","utf-8''T%C3%A4st.txt"),
... ("baz*0","two"),("baz*1","-part")])[1:]]
[('foo', 'bar'), ('baz', 'two-part'), ('name', '"Täst.txt"')]
Итак, кажется, что для использования всего этого механизма я должен добавить еще один шаг, чтобы исключить третий элемент любого кортежа, с которым я столкнулся. Это правда, или я пропустил какой-то момент здесь? Мне пришлось выяснить много из вышеперечисленного с помощью исходного кода, так как документы немного расплывчаты в деталях. Я не могу представить, что могло бы занять этот избирательный случай. Есть ли смысл?
Как лучше всего использовать эти функции?
Лучшее, что я нашел до сих пор, это email.message.Message
реализация. Там процесс выглядит примерно так, как описано выше, но каждое поле получает без кавычек через _unquotevalue
после decode_params
и только get_filename
и get_boundary
сворачивают свои значения, все остальные возвращают кортеж. Надеюсь, что есть что-то более полезное.