您将 Unicode 与 UTF-8 混淆了。 Latin-1 是 Unicode 的子集,但不是 UTF-8 的子集。 避免像瘟疫一样考虑单个代码单元。只需使用代码点。不要考虑 UTF-8。请考虑使用 Unicode。这就是你感到困惑的地方。
演示程序源代码
在 Python 中使用 Unicode 非常容易。尤其是 Python 3 和宽版本,这是我使用 Python 的唯一方式,但如果您小心坚持使用 UTF-8,您仍然可以在窄版本下使用旧版 Python 2。
为此,请始终将您的源代码编码和输出编码正确地转换为 UTF-8。现在停止考虑 UTF-anything,在整个 Python 程序中只使用 UTF-8 文字、逻辑代码点编号或符号字符名称。
这是带有行号的源代码:
% cat -n /tmp/py
1 #!/usr/bin/env python3.2
2 # -*- coding: UTF-8 -*-
3
4 from __future__ import unicode_literals
5 from __future__ import print_function
6
7 import sys
8 import os
9 import re
10
11 if not (("PYTHONIOENCODING" in os.environ)
12 and
13 re.search("^utf-?8$", os.environ["PYTHONIOENCODING"], re.I)):
14 sys.stderr.write(sys.argv[0] + ": Please set your PYTHONIOENCODING envariable to utf8\n")
15 sys.exit(1)
16
17 print('1a: el ni\xF1o')
18 print('2a: el nin\u0303o')
19
20 print('1a: el niño')
21 print('2b: el niño')
22
23 print('1c: el ni\N{LATIN SMALL LETTER N WITH TILDE}o')
24 print('2c: el nin\N{COMBINING TILDE}o')
这里是带有非 ASCII 字符 uniquoted 的打印函数,使用 \x{⋯} 表示法:
% grep -n ^print /tmp/py | uniquote -x
17:print('1a: el ni\xF1o')
18:print('2a: el nin\u0303o')
20:print('1b: el ni\x{F1}o')
21:print('2b: el nin\x{303}o')
23:print('1c: el ni\N{LATIN SMALL LETTER N WITH TILDE}o')
24:print('2c: el nin\N{COMBINING TILDE}o')
演示程序的示例运行
这是该程序的示例运行,显示了执行此操作的三种不同方式(a、b 和 c):第一个设置为源代码中的文字(将受 StackOverflow 的 NFC 转换的影响,因此不能值得信赖!!!),第二组分别带有 numeric Unicode code points 和 symbolic Unicode character names,同样是 uniquoted,因此您可以看到真正的内容:
% python /tmp/py
1a: el niño
2a: el niño
1b: el niño
2b: el niño
1c: el niño
2c: el niño
% python /tmp/py | uniquote -x
1a: el ni\x{F1}o
2a: el nin\x{303}o
1b: el ni\x{F1}o
2b: el nin\x{303}o
1c: el ni\x{F1}o
2c: el nin\x{303}o
% python /tmp/py | uniquote -v
1a: el ni\N{LATIN SMALL LETTER N WITH TILDE}o
2a: el nin\N{COMBINING TILDE}o
1b: el ni\N{LATIN SMALL LETTER N WITH TILDE}o
2b: el nin\N{COMBINING TILDE}o
1c: el ni\N{LATIN SMALL LETTER N WITH TILDE}o
2c: el nin\N{COMBINING TILDE}o
我真的不喜欢看二进制,但这是二进制字节的样子:
% python /tmp/py | uniquote -b
1a: el ni\xC3\xB1o
2a: el nin\xCC\x83o
1b: el ni\xC3\xB1o
2b: el nin\xCC\x83o
1c: el ni\xC3\xB1o
2c: el nin\xCC\x83o
故事的寓意
即使您使用 UTF-8 源代码,您也应该只考虑并使用逻辑 Unicode 代码点编号(或符号命名字符),而不是构成 UTF-8 串行表示的单个 8 位代码单元(或UTF-16 的问题)。需要代码单元而不是代码点是极其罕见的,它只会让您感到困惑。
如果您使用更广泛的 Python3 版本,您将获得比使用这些选择的替代方案更可靠的行为,但这是 UTF-32 问题,而不是 UTF-8 问题。如果您顺其自然,UTF-32 和 UTF-8 都很容易使用。