如何判断字符串是否为Base64编码
我收到了很多来自不同来源的邮件。这些邮件都有附件,其中很多附件的名字是中文,所以这些名字在邮件客户端中被转换成了base64格式。
当我收到这些邮件时,我想解码这些名字。但是还有一些名字并不是base64格式的。我该如何判断一个字符串是否是base64格式,使用jython编程语言呢?
也就是说:
第一个附件:
------=_NextPart_000_0091_01C940CC.EF5AC860
Content-Type: application/vnd.ms-excel;
name="Copy of Book1.xls"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="Copy of Book1.xls"
第二个附件:
------=_NextPart_000_0091_01C940CC.EF5AC860
Content-Type: application/vnd.ms-excel;
name="=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?="
请注意,两个“Content-Transfer-Encoding”都是base64格式。
6 个回答
@gnud, @edg - 除非我理解错了,他在问的是文件名,而不是文件内容。
@setori - Content-Transfer-Encoding 是在告诉你文件内容是怎么编码的,而不是“文件名”。
我不是专家,但文件名中的这一部分是在告诉他后面的字符是什么:
=?gb2312?B?
我在找相关的文档,RFC里有... 啊!找到了: https://www.rfc-editor.org/rfc/rfc2047
RFC里说:
一般来说,“编码词”是一个可打印的ASCII字符序列,它以“=?”开头,以“?=”结尾,中间有两个“?”。
另外可以看看SharpMimeTools里的代码,这是一个我在我的缺陷跟踪应用中使用的MIME解析器(用C#写的),BugTracker.NET
这个头部的值告诉你这些信息:
=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?= "=?" introduces an encoded value "gb2312" denotes the character encoding of the original value "B" denotes that B-encoding (equal to Base64) was used (the alternative is "Q", which refers to something close to quoted-printable) "?" functions as a separator "uLG..." is the actual value, encoded using the encoding specified before "?=" ends the encoded value
所以在"?"上进行分割实际上会得到这个(JSON格式)
["=", "gb2312", "B", "uLGxvmhlbrixsb5nLnhscw==", "="]
在得到的数组中,如果"B"在第2个位置,那么第3个位置上会有一个经过Base64编码的字符串。解码后,记得关注第1个位置的编码信息,最好是根据这些信息把整个内容转换成UTF-8格式。
请注意,两个
Content-Transfer-Encoding
都是使用 base64 编码的。
在这种情况下,这个 Content-Transfer-Encoding
不太相关,它只适用于邮件的主体内容,而不是邮件的头部信息。
=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?=
这是一个经过 RFC2047 编码的头部信息。用来解码它的标准库函数是 email.header.decode_header
。不过,解码后的结果还需要稍微处理一下才能理解:
import email.header
x= '=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?='
try:
name= u''.join([
unicode(b, e or 'ascii') for b, e in email.header.decode_header(x)
])
except email.Errors.HeaderParseError:
pass # leave name as it was
但是……
Content-Type: application/vnd.ms-excel;
name="=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?="
这完全是错误的。是什么邮件程序生成的这个?RFC2047 编码只能出现在原子(atom)中,而引用字符串(quoted-string)并不是原子。RFC2047 第5条明确禁止这样做:
- 一个“编码词”不能出现在“引用字符串”中。
当参数头部包含长字符串或 Unicode 字符时,正确的编码方式是 RFC2231,这又是一个复杂的问题。不过,你应该使用一个标准的邮件解析库,它会为你处理这些事情。
所以,如果你想的话,可以检测文件名参数中的 '=?'
,并尝试通过 RFC2047 解码它。然而,严格来说,正确的做法是相信邮件程序的说法,真的把文件称为 =?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?=
!