处理命令行参数中的 unicode 字符

Processing unicode characters in command line arguments

我在 Raspberry Pi(Raspbian 基于 Debian Linux OS)上有一个项目,我必须将命令行参数传递给 Python 3节目。我需要能够传递一个 unicode 字符串。

我不确定应该如何设置。很明显,在将数据传递给 Python.

之前,命令行字符串要经过几次转换

让我们从我在终端会话中按下所需的击键时可以正确看到 Unicode 字符这一事实开始。这是一些测试代码:

$ echo "ā" > test.txt
$ cat test.txt
ā
$ hexdump test.txt 
0000000 81c4 000a                              
0000003

那个 0x81c4 字,或双字节序列 0xc4+0x81 被“ā”编码为 UTF-8。

现在,如果我尝试将相同的字符传递给 Python,我会得到一个包含奇怪字符代码的双字符字符串:

import sys
param = sys.argv[1]
print([hex(ord(char)) for char in param])

$ python test.py ā
['0xdcc4', '0xdc81']

可以注意到,字符编码与0xc4+0x81字节序列相关,但这里每个字节都加上0xdc00。

如果我进入交互式控制台,unicode字符操作与普通字符一样:

>>> txt = 'ā'
>>> len(txt)
1
>>> hex(ord(txt[0]))
'0x101'

0x101 是字符“ā”的正确代码点。

所以,我的问题是,如何可靠地将双字符 ['0xdcc4', '0xdc81'] 字符串转换为单字符字符串“ā”,从而在所有平台上都适用?

我不确定这到底是在哪一点发生的,但是命令行参数显然应该只包含 ASCII 字符,并且要将字节数组解码为字符串,使用 bytes.decode(encoding, errors)

param = b'\xc4\x81'.decode('ASCII', 'surrogateescape')
print(param == '\udcc4\udc81') # True

当解码器偶然发现非 ASCII 字符时,它会根据选定的错误处理程序处理解码。在这种情况下,surrogateescape 错误处理程序将字节替换为从 U+DC80 到 U+DCFF 的单个代理代码。

因此,解决此问题的方法是使用相同的 surrogateescape 错误处理程序将错误解码的字符串编码回字节数组,然后将其解码为 utf-8:

import sys
param = sys.argv[1]
param_unicode = param.encode('ASCII', 'surrogateescape').decode('utf-8')
print(param_unicode)

$ python test.py ā
ā

但是,如果命令行参数真的总是使用 ASCII 编码解码,则应该验证一下。可能不同平台不一样,可以配置。