如何使用 python 解码此附件文件名?
How to get decode this attachment filename with python?
我已经在我的代码中解码了很多电子邮件附件文件名。
但是这个特定的文件名破坏了我的代码。
这是一个最小的例子:
from email.header import decode_header
encoded_filename='=?UTF-8?B?U2FsZXNJbnZvaWNl?==?UTF-8?B?LVJlcG9ydC5wZGY=?='
decoded_header=decode_header(encoded_filename) # --> [('SalesInvoiceQ1|\x04\xb5I\x95\xc1\xbd\xc9\xd0\xb9\xc1\x91\x98', 'utf-8')]
filename=str(decoded_header[0][0]).decode(decoded_header[0][1])
异常:
UnicodeDecodeError: 'utf8' codec can't decode byte 0xb5 in position 16: invalid start byte
别问我怎么做的,Thunderbird 能够将这个文件名解码为:SalesInvoice-Report.pdf
我如何用 python 解码它,就像电子邮件客户端显然能够做到的那样?
header 中有 两个 Encoded-Word 个部分。你必须检测一个结束和一个开始的地方:
>>> print decode_header(encoded_filename[:28])[0]
('SalesInvoice', 'utf-8')
>>> print decode_header(encoded_filename[28:])[0]
('-Report.pdf', 'utf-8')
显然这就是 Thunderbird 在这种情况下所做的;将字符串拆分为 =?encoding?data?=
个块。 通常这些应该由\r\n
(CARRIAGE RETURN + LINE FEED)字符分隔,但在你的情况下它们被混在一起。如果您 re-introduce \r\n
分隔符值正确解码:
>>> decode_header(encoded_filename[:28] + '\r\n' + encoded_filename[28:])[0]
('SalesInvoice-Report.pdf', 'utf-8')
您可以使用正则表达式来提取部分和 re-introduce 分隔符:
import re
from email.header import decode_header
quopri_entry = re.compile(r'=\?[\w-]+\?[QB]\?[^?]+?\?=')
def decode_multiple(encoded, _pattern=quopri_entry):
fixed = '\r\n'.join(_pattern.findall(encoded))
output = [b.decode(c) for b, c in decode_header(fixed)]
return ''.join(output)
演示:
>>> encoded_filename = '=?UTF-8?B?U2FsZXNJbnZvaWNl?==?UTF-8?B?LVJlcG9ydC5wZGY=?='
>>> decode_multiple(encoded_filename)
u'SalesInvoice-Report.pdf'
当然,可能首先是您在阅读 header 时遇到了错误。确保在提取 encoded_filename
值时不会意外破坏现有的 \r\n
分隔符。
我已经在我的代码中解码了很多电子邮件附件文件名。
但是这个特定的文件名破坏了我的代码。
这是一个最小的例子:
from email.header import decode_header
encoded_filename='=?UTF-8?B?U2FsZXNJbnZvaWNl?==?UTF-8?B?LVJlcG9ydC5wZGY=?='
decoded_header=decode_header(encoded_filename) # --> [('SalesInvoiceQ1|\x04\xb5I\x95\xc1\xbd\xc9\xd0\xb9\xc1\x91\x98', 'utf-8')]
filename=str(decoded_header[0][0]).decode(decoded_header[0][1])
异常:
UnicodeDecodeError: 'utf8' codec can't decode byte 0xb5 in position 16: invalid start byte
别问我怎么做的,Thunderbird 能够将这个文件名解码为:SalesInvoice-Report.pdf
我如何用 python 解码它,就像电子邮件客户端显然能够做到的那样?
header 中有 两个 Encoded-Word 个部分。你必须检测一个结束和一个开始的地方:
>>> print decode_header(encoded_filename[:28])[0]
('SalesInvoice', 'utf-8')
>>> print decode_header(encoded_filename[28:])[0]
('-Report.pdf', 'utf-8')
显然这就是 Thunderbird 在这种情况下所做的;将字符串拆分为 =?encoding?data?=
个块。 通常这些应该由\r\n
(CARRIAGE RETURN + LINE FEED)字符分隔,但在你的情况下它们被混在一起。如果您 re-introduce \r\n
分隔符值正确解码:
>>> decode_header(encoded_filename[:28] + '\r\n' + encoded_filename[28:])[0]
('SalesInvoice-Report.pdf', 'utf-8')
您可以使用正则表达式来提取部分和 re-introduce 分隔符:
import re
from email.header import decode_header
quopri_entry = re.compile(r'=\?[\w-]+\?[QB]\?[^?]+?\?=')
def decode_multiple(encoded, _pattern=quopri_entry):
fixed = '\r\n'.join(_pattern.findall(encoded))
output = [b.decode(c) for b, c in decode_header(fixed)]
return ''.join(output)
演示:
>>> encoded_filename = '=?UTF-8?B?U2FsZXNJbnZvaWNl?==?UTF-8?B?LVJlcG9ydC5wZGY=?='
>>> decode_multiple(encoded_filename)
u'SalesInvoice-Report.pdf'
当然,可能首先是您在阅读 header 时遇到了错误。确保在提取 encoded_filename
值时不会意外破坏现有的 \r\n
分隔符。