python 中的 UTF8 编码和解码

UTF8 Encoding and decoding in python

我有一个从 Java 传输到 python 的 UTF8 字符串。

最终结果是

'\xe0\xb8\x9a\xe0\xb8\x99'

因此例如

a = '\xe0\xb8\x9a\xe0\xb8\x99'

a.decode('utf-8') 

给我结果

u'\u0e1a\u0e19'

然而,我很好奇的是,既然字节是作为 UTF-8 传输的,为什么会是

'\xe0\xb8\x9a\xe0\xb8\x99'

而不是 u'\u0e1a\u0e19'

如果我要编码 (u'\u0e1a\u0e19') 我会回来 '\xe0\xb8\x9a\xe0\xb8\x99'.

那么这两者之间的内在区别是什么以及我如何真正理解何时使用解码和编码。

UTF8 字符串不足以描述语句 '\xe0\xb8\x9a\xe0\xb8\x99' 是;它确实应该称为 unicode 字符串的 UTF8 编码。

Python2的unicode类型和Python3的str类型表示一串unicode码位,所以语句u'\u0e1a\u0e19'就是python 表示两个代码点 U+0E1A U+0E19 并且在人类术语中它将呈现为 บน.

至于解释整个 encodedecode 调用,我们将使用您的示例。您从 Java 返回的是原始字节流,因此要使其用作人类文本,您需要按顺序 decode '\xe0\xb8\x9a\xe0\xb8\x99' 作为 utf-8 编码输入将其返回到它们所代表的 unicode 代码点(即 u'\u0e1a\u0e19')。在该 unicode 代码字符串上调用 encode 返回字节列表(在 Python 2 中它将是 str 类型,而 Python 3 它实际上是bytes 类型)将返回到 '\xe0\xb8\x9a\xe0\xb8\x99'.

的字节序列

当然,您可以将这些 un​​icode 代码点编码为其他编码,例如 UTF16 编码,在小端平台上它将产生字节 '\xff\xfe\x1a\x0e\x19\x0e',或者使用将这些代码点编码为非 unicode 编码.由于这看起来像泰语,我们可以为此使用 iso8859-11 编码,它将被编码为字节 '\xba\xb9' - 但这不是跨平台的,因为它只会在为此配置的系统上显示为泰语特定的编码。这是 Unicode 被发明的原因之一,因为这些字节 '\xba\xb9' 可以使用 iso8859-1 编码解码,这将呈现为 º¹iso8859-11บน.

简而言之,'\xe0\xb8\x9a\xe0\xb8\x99'是Python语法中u'\u0e1a\u0e19'的unicode代码点的UTF8编码。原始字节(通过网络传输,从文件中读取)通常不是 unicode 代码点的形式,它们必须被解码为 un​​icode 代码点。 Unicode 代码点不是一种编码,当通过线路发送(或写入文件)时,必须将其编码为某种 unicode 代码点的字节表示形式,在许多情况下是 utf-8,因为它具有最大的可移植性。

最后,您应该阅读以下内容:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

'\xe0\xb8\x9a\xe0\xb8\x99' 只是一系列字节。 已选择将其解释为 UTF-8,当您这样做时,您可以将其解码为一系列 unicode 字符,U+e1a 和 U+e19。

序列U+e1a,U+e19可以表示为u'\u0e1a\u0e19',但在某种意义上,表示与'\xe0\xb8\x9a\xe0\xb8\x99'一样随意。它是 "natural",这就是 Python 以这种方式打印它们的原因,但它是低效的,这就是为什么还有各种其他编码方案,包括 UTF-8

事实上,“'\xe0\xb8\x9a\xe0\xb8\x99' 是一系列字节”对我来说有点误导。它是一系列字节的默认表示,224,后面是 184,依此类推。

Python 有一个字节序列的概念,它有一个单独的 unicode 字符序列概念。 encodedecode 表示这两个概念之间的一种映射方式。

有帮助吗?