如何在Python 3.x中确定Unicode字符串的显示宽度,并且是否有一种方法可以使用该信息来将这些字符串与str.format()
对齐?
动机示例: 在控制台打印字符串表格。 其中一些字符串包含非ASCII字符。
>>> for title in d.keys():
>>> print("{:<20} | {}".format(title, d[title]))
zootehni- | zooteh.
zootekni- | zootek.
zoothèque | zooth.
zooveterinar- | zoovet.
zoovetinstitut- | zoovetinst.
母 | 母母
>>> s = 'è'
>>> len(s)
2
>>> [ord(c) for c in s]
[101, 768]
>>> unicodedata.name(s[1])
'COMBINING GRAVE ACCENT'
>>> s2 = '母'
>>> len(s2)
1
正如所见,str.format()
简单地将字符串中的代码点数(len(s)
)作为宽度,导致输出结果中的列不对齐。在 unicodedata
模块中搜索,我没有找到任何建议解决此问题的信息。
Unicode 标准化 可以解决 è 的问题,但无法解决亚洲字符的问题,因为它们通常具有更大的显示宽度。同样,存在零宽度的 Unicode 字符(例如,用于在单词内允许换行的零宽度空格)。您不能通过标准化来解决这些问题,因此请不要建议“标准化字符串”。
编辑:添加有关标准化的信息。
编辑2:在我的原始数据集中还有一些欧洲组合字符,即使经过标准化后也不会得出单个代码点:
zwemwater | zwemw.
zwia̢z- | zw.
>>> s3 = 'a\u0322' # The 'a + combining retroflex hook below' from zwiaz
>>> len(unicodedata.normalize('NFC', s3))
2
s2 = unicodedata.normalize('NFC', s)
会返回所需的“LATIN SMALL LETTER E WITH GRAVE”。然后调用unicodedata.east_asian_width(s2)
会返回"A"
,文档很好地告诉我们它是“模棱两可”的 - 尽管它的显示宽度肯定为1。 - Christian Aichinger