【Python】字符串显示宽度计算的方法

字符串显示宽度计算的方法

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)的原始作者小林剣本人也承认这一点。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

田辛 | 田豆芽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值