在Python中显示Unicode字符串的宽度

Chr*_*ger 7 python string unicode width python-unicode

如何确定Python 3.x中Unicode字符串的显示宽度,以及是否有一种方法可以使用该信息将这些字符串与对齐str.format()

激励示例:将字符串表打印到控制台。一些字符串包含非ASCII字符。

>>> for title in d.keys():
>>>     print("{:<20} | {}".format(title, d[title]))

    zootehni-           | zooteh.
    zootekni-           | zootek.
    zoothe?que          | zooth.
    zooveterinar-       | zoovet.
    zoovetinstitut-     | zoovetinst.
    ?                   | ??

>>> s = 'e?'
>>> len(s)
    2
>>> [ord(c) for c in s]
    [101, 768]
>>> unicodedata.name(s[1])
    'COMBINING GRAVE ACCENT'
>>> s2 = '?'
>>> len(s2)
    1
Run Code Online (Sandbox Code Playgroud)

可以看出,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
Run Code Online (Sandbox Code Playgroud)

Aar*_*lla 4

您有多种选择:

  1. 某些控制台支持转义序列以实现光标的像素精确定位。不过,可能会导致一些叠印。

    历史记录:这种方法用于 Amiga 终端,通过打印一行文本,然后将光标向下移动一个像素,在控制台窗口中显示图像。文本行的剩余像素慢慢地构建了图像。

  2. 在代码中创建一个表,其中包含控制台/终端窗口中使用的字体中的所有 Unicode 字符的实际(像素)宽度。使用 UI 框架和一个小型 Python 脚本来生成此表。

    然后添加使用此表计算文本实际宽度的代码。不过,结果可能不是控制台中字符宽度的倍数。与像素精确的光标移动一起,这可能会解决您的问题。

    注意:您必须为连字 (fi, fl) 和合成词添加特殊处理。或者,您可以在不打开窗口的情况下加载 UI 框架,并使用图形基元来计算字符串宽度。

  3. 使用制表符 ( \t) 进行缩进。但只有当您的 shell 实际上使用真实文本宽度来放置光标时,这才会有帮助。许多终端只会简单地计算字符数。

  4. 创建一个包含表格的 HTML 文件并在浏览器中查看它。