繁体   English   中英

为什么我可以在没有任何 UnicodeEncodeError/UnicodeDecodeError 的情况下将 UTF-8 字节字符串解码为 ISO8859-1 并再次返回?

[英]How come I can decode a UTF-8 byte string to ISO8859-1 and back again without any UnicodeEncodeError/UnicodeDecodeError?

以下如何在 Python 中没有任何错误的情况下工作?

>>> '你好'.encode('UTF-8').decode('ISO8859-1')
'ä½\xa0好'
>>> _.encode('ISO8859-1').decode('UTF-8')
'你好'

我原以为它会因 UnicodeEncodeError 或 UnicodeDecodeError 而失败

是否有 ISO8859-1 和 UTF-8 的某些属性,以便我可以采用任何 UTF-8 编码的字符串并将其解码为 ISO8859-1 字符串,以后可以将其反转以获得原始 ZAE3B3DF9970B49B95723E 字符串?

我正在使用仅支持 ISO8859-1 字符集的旧数据库。 似乎开发人员能够通过将 UTF-8 编码字符串解码为 ISO8859-1,并将生成的垃圾字符串存储在数据库中,从而将中文和其他语言存储在该数据库中。 查询此数据库的下游系统必须在 ISO8859-1 中对垃圾字符串进行编码,然后使用 UTF-8 对结果进行解码以获得正确的字符串。

我会假设这样的过程根本行不通。

我错过了什么?


ISO-8859-1 的特殊属性是它所代表的 256 个字符与前 256 个 Unicode 码点 1:1 对应,因此字节 00h 解码为 U+0000,字节 FFh 解码为 U+00FF。

因此,如果您编码为 UTF-8 并解码为 ISO-8859-1,您将得到一个 Unicode 字符串,该字符串由其值与编码的 UTF-8 字节匹配的代码点组成:

>>> s = '你好'
>>> s.encode('utf8').hex()
'e4bda0e5a5bd'
>>> s.encode('utf8').decode('iso-8859-1')
'ä½\xa0好'
>>> for c in u:
...  print(f'{c} U+{ord(c):04X}')
...
ä U+00E4   # Unicode code points are the same as the bytes of UTF-8.
½ U+00BD
  U+00A0
å U+00E5
¥ U+00A5
½ U+00BD
>>> u.encode('iso-8859-1').hex()  # transform back to bytes.
'e4bda0e5a5bd'
>>> u.encode('iso-8859-1').decode('utf8')   # and decode to UTF-8 again.
'你好'

任何具有所有 256 字节表示的 8 位编码也可以工作,只是不会是 1:1 映射。 Code Page 1256 就是这样一种编码:

>>> for c in s.encode('utf8').decode('cp1256'):
...  print(f'{c} U+{ord(c):04X}')
...
ن U+0646   # This would still .encode('cp1256') back to byte E4, for example
½ U+00BD
  U+00A0
ه U+0647
¥ U+00A5
½ U+00BD

不,ISO8859-1 没有特殊属性,但在许多 8 位编码中共有一个属性:它们接受从 0 到 255 的所有字节。

因此,您decode('ISO8859-1')只是以独特的方式将字节转换为 256 个字符(和控制代码)。 然后你做相反的动作,所以你什么也没有损失。

大多数旧的 8 位编码都会发生这种情况:它们应该只有一个相应的 Unicode 代码点(因为 Python 期望字符串是 Unicode 字符串)。

注意:真的 ISO8859-1 与 Unicode 是特殊的:Unicode 的前 256 个代码点对应于 Latin-1 字符(具有相同的数字)。 但这对您的实验无关紧要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM