如果一个字符串只包含 ASCII,它是否等于该字符串的字节数?
不,它在 Python 3 中是不相等的:
>>> '1' == b'1'
False
bytes
对象不等于str
(Unicode string) 对象,与整数不等于字符串的方式类似:
>>> '1' == 1
False
在某些编程语言中,上述比较是正确的,例如在 Python 2 中:
>>> b'1' == u'1'
True
and 1 == '1'
在 Perl 中:
$ perl -e "print qq(True\n) if 1 == q(1)"
True
你的问题很好地说明了为什么stricterPython 3 的行为更可取。它迫使程序员面对他们的文本/字节误解,而不必等待他们的代码因某些输入而中断。
yes. 字符串是 Unicode 代码点的不可变序列 http://docs.python.org/3/library/stdtypes.html#textseq在Python 3中。
大多数电子邮件作为 7 位消息传输(ASCII 范围:十六进制00-7F
)。尽管“几乎所有现代电子邮件服务器都是 8 位干净的。” http://en.wikipedia.org/wiki/8-bit_clean即,8 位内容不会被损坏。和8BITMIME 扩展 https://www.rfc-editor.org/rfc/rfc6152制裁某些 8 位内容的传递。
换句话说:电子邮件是not始终为 ASCII.
ASCII 是一种字符编码。你可以decode some使用 US-ASCII 字符编码将字节序列转换为 Unicode。 Unicode 字符串没有关联的字符编码,即,您可以encode使用可以表示相应 Unicode 代码点的任何字符编码将它们转换为字节。
因此,传入的电子邮件是纯 ASCII(这是有效的 Unicode),因此 SMTPD DATA 字符串与 SMPTD 接收到的原始字节完全相同。它是否正确?
如果输入在 ascii 范围内,则data.decode('ascii', 'strict').encode('ascii') == data
。
尽管库/smtpd.py http://hg.python.org/cpython/file/3.3/Lib/smtpd.py#l329对输入数据进行一些转换(根据RFC 5321
)因此您得到的内容为data
即使输入是纯 ASCII,也可能会有所不同。
“如何将 Python 3 的 SMTPD 数据准确地保存到文件中接收到的字节?”
我的目标不是找到格式错误的电子邮件,而是将入站电子邮件以它们到达的二进制/字节形式精确保存到磁盘。
您链接的错误(smtpd.py 不应解码 utf-8 http://bugs.python.org/issue19662) 使 smptd.py 非 8 位干净。
你可以覆盖SMTPChannel.collect_incoming_data方法来自smtpd.py http://hg.python.org/cpython/file/3.3/Lib/smtpd.py#l278按原样保存传入字节。
“ASCII 文本字符串也是有效的 UTF-8 文本。” http://docs.python.org/3.3/howto/unicode.html#encodings
是真的。这是 UTF-8 编码的一个很好的特性。如果您可以使用 US-ASCII 字符编码将字节序列解码为 Unicode,那么您也可以使用 UTF-8 字符编码将字节解码(并且在两种情况下生成的 Unicode 代码点相同)。
smptd.py
应该使用过latin1
(它解码任何字节序列)或ascii
(使用“严格”错误处理程序在任何非 ASCII 字节上失败)而不是utf-8
(它允许一些非 ASCII 字节——不好)。
记住:
- 某些电子邮件的字节可能超出 ASCII 范围
- 根据 RFC 5321 的去透明性不会按原样保留输入字节,即使它们都在 ascii 范围内