字符串显示宽度计算的方法
文章目录
1. 缘起
最近两天要给公司的小朋友写个工具,需要在控制台输出一些信息。 开始以为是一件简单的事情。 但是谁让田老师是处女座呢,追求完美不是。
如果要在终端输出格式的信息,计算字符串的显示宽度就是必要的事情。 但是对与这个看似简单的功能,Python的len()函数并不能有效的解决这个问题,只能自己研究了。 (多么怀念VB里面的LenB()函数啊。)
2. 研究方向
既然len()函数无法解决中文的显示长度问题。 那么只能使用标准库unicodedata
中的east_asian_width()
函数来解决问题。这个函数可以根据给到的unicode字符的值,判断是半角还是全角。
找了一下中文互联网上的资料,还没有文章把这个问题说透。 所以写成此文记录之。
3. 核心内容
这里主要要说明3个问题:
East Asian Width
这个概念unicodedata.east_asian_width()
函数的基本使用(不只是中文)- 实际使用案例
- 注意事项
3.1 什么是East Asian Width
“东亚字符宽度”是 Unicode 标准附件之一。 它定义了East_Asian_Width参考特征,该特征提供有关 Unicode 中每个字符的字符宽度的提示。
East Asian Width
(东亚字符宽度)这个概念被定义是在《Unicode® 标准附录 #11》中。 链接为:UAX #11:东亚宽度 (unicode.org)
对于东亚语言来说,主要是固定间距字体。 要处理的内容包括半角英数字、正常的汉字、半角显示的特殊字符,以及从日语shift-jis编码过来的颜文字等各种特殊字符。
以田老师的项目经验,中文在此方面还算是相对简单的。 中等复杂的是日语,既有类似与中文的“日语汉字”、平假名(あいうえお)、片假名(アイウエオ)、还有小子表示的片假名(アイウエオ)。 当然,最复杂的还要数西里尔语言体系、阿拉伯语、希腊语方面的应用。
Python通过unicodedata.east_asian_width()
通过6种分类,给出每一个unicode字符的宽度。这六种分类分别是:
- F(全角) - 全角字母数字等。
- H(半角) - 所谓的半角假名(アイウエオ)等。
- W(宽) - 上述字符以外的字符,在传统字符代码中称为全角字符。 汉字、日语假名字符和描述符号(例如标点符号),这些符号仅用于东亚的组版本。
- Na(窄) - 上述字符以外的字符,在传统字符代码中存在相应的所谓全角字符。 所谓的半角字母数字等。
- A(模糊) - 字符宽度因上下文而异的字符。 它甚至不能用简单的中文和日语的全半角去理解。 比如希腊语、西里尔文等。 在东亚的传统字符代码中可以被视为所谓的全角。
- N(中性) - 不属于上述任何字符的字符。 它通常不出现在东亚的组版本中,也不是全角的或半角的。 阿拉伯字母等。
3.2 使用案例
3.2.1 六种文字分类的分别举例输出
import unicodedata
if __name__ == "__main__":
print(unicodedata.east_asian_width('A')) # 全角字母A
print(unicodedata.east_asian_width('ア')) # 日语半角假名
print(unicodedata.east_asian_width('田')) # 汉字‘田’
print(unicodedata.east_asian_width('k')) # 英语字母k
print(unicodedata.east_asian_width('Б')) # 西里尔语系,俄语字母Б
print(unicodedata.east_asian_width('ل')) # 阿拉伯语ل
输出结果
D:\Python-grp\miniconda3_data\env\py3.10\python.exe E:\develop\python\pystudy\src\unicode_east_asian_width.py
F
H
W
Na
A
N
进程已结束,退出代码0
3.2.2 unicodedata.east_asian_width
常见错误
本函数的常见错误,就是输入的是字符串而不是字符。比如:
>>> import unicodedata
>>> unicodedata.east_asian_width('田辛')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: east_asian_width() argument must be a unicode character, not str
>>> unicodedata.east_asian_width('田')
'W'
>>> unicodedata.east_asian_width('辛')
'W'
>>>
3.3 实际应用
def get_east_asian_width_count(text):
count = 0
for c in text:
if unicodedata.east_asian_width(c) in 'FWA':
count += 2
else:
count += 1
return count
函数调用
if __name__ == "__main__":
print(get_east_asian_width_count('田辛'))
print(get_east_asian_width_count('pythonとは?'))
print(get_east_asian_width_count('1234567890'))
输出结果
D:\Python-grp\miniconda3_data\env\py3.10\python.exe E:\develop\python\pystudy\src\unicode_east_asian_width.py
4
12
10
进程已结束,退出代码0
3.4 注意事项
因为项目经验有限,本文在处理中文,基本日文语言中没有问题。 涉及到俄文、阿拉伯语项目可能还有不足之处。当然UAX #11: East Asian Width (unicode.org)的原始作者小林剣本人也承认这一点。