Python中显示Unicode字符串的宽度
我该如何在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
1 个回答
你有几个选择:
有些控制台支持特殊的转义序列,可以让光标精确到像素级别地定位。不过,这可能会导致一些文字重叠的问题。
历史小知识:这种方法曾在Amiga终端中使用,通过在控制台窗口中打印一行文本,然后将光标向下移动一个像素来显示图像。剩下的文本像素慢慢拼凑成了一幅图像。
在你的代码中创建一个表格,里面包含控制台/终端窗口中使用的字体所有Unicode字符的实际(像素)宽度。可以使用一个UI框架和一个小的Python脚本来生成这个表格。
然后添加代码,通过这个表格来计算文本的实际宽度。不过,结果可能并不是控制台字符宽度的整数倍。结合像素级的光标移动,这可能会解决你的问题。
注意:你需要特别处理一些连字(比如fi、fl)和复合字符。另外,你也可以在不打开窗口的情况下加载一个UI框架,使用图形原语来计算字符串的宽度。
使用制表符字符(
\t
)来缩进。不过,这只有在你的终端实际上使用真实文本宽度来放置光标时才有用。很多终端只是简单地按字符计数。创建一个包含表格的HTML文件,然后在浏览器中查看它。