V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
songdg
V2EX  ›  Python

如何确定字符串显示的宽度

  •  
  •   songdg · 2020-05-17 14:32:02 +08:00 · 4392 次点击
    这是一个创建于 1652 天前的主题,其中的信息可能已经有所发展或是发生改变。

    例如 a = 'PM2.5' b = '地下管道' c = '空铁 WIFI',a 、b 、c 的宽度分别为 5 、8 、8,字母、数字的宽度为 1,汉字的宽度为 2 。用 len 函数得到的结果为 5 、4 、6 ;用 sys.getsizeof 得到的结果为 54 、82 、86,当字符串中含有混合字符时也不能用来推导显示宽度。请教还有没有其他方法。

    21 条回复    2020-05-20 17:54:26 +08:00
    codehz
        1
    codehz  
       2020-05-17 14:35:45 +08:00
    用 freetype 的 api 真实可以取得各种测量属性,当然,需要指定字体
    xcstream
        2
    xcstream  
       2020-05-17 14:43:09 +08:00
    用等宽字体 判断中英文
    ClericPy
        3
    ClericPy  
       2020-05-17 14:50:22 +08:00
    暂时能想到的就只有正则出中文字数... len + len_中
    secondwtq
        4
    secondwtq  
       2020-05-17 14:53:20 +08:00
    这么复杂的问题你确定能在中文社区问出答案来么……
    0x5f
        5
    0x5f  
       2020-05-17 15:04:03 +08:00   ❤️ 1
    如果是获取显示在图片上的宽度话 pil 库里有个 ImageFont.getsize()可以返回渲染后文字长宽
    JCZ2MkKb5S8ZX9pq
        6
    JCZ2MkKb5S8ZX9pq  
       2020-05-17 15:52:43 +08:00   ❤️ 1
    我自己在用的是这个

    width = (len(string) + len(string.encode('utf-8'))) // 2 # py3

    前置还要移掉点 anis 之类的玩意儿,中日英目前用下来还好,日文小字也算 2 。
    但是类似西班牙语法语那种带小尾巴的,unicode 有种写法是尾巴单独用一个字符,那个也许会有问题。
    JCZ2MkKb5S8ZX9pq
        7
    JCZ2MkKb5S8ZX9pq  
       2020-05-17 15:56:55 +08:00
    @ClericPy
    看看我上面这个,利用了编码之后中文 1 变 3 的特性,平时主要处理中英文还好,看看会有什么问题吗?

    @songdg
    另外我想起来类似 preetrytable 之类的模块,好像中文宽度都给处理过了,有兴趣也可以直接看看人家源码。
    lithbitren
        8
    lithbitren  
       2020-05-17 15:59:44 +08:00
    只看中英文和常用符号还好,加上其他语言符号是真 jb 复杂
    JCZ2MkKb5S8ZX9pq
        9
    JCZ2MkKb5S8ZX9pq  
       2020-05-17 16:03:25 +08:00
    另外我上面说的都是我在程序里打印结果,然是是等宽字体的情况下的占位数。
    如果是显示的话,要看显示在什么地方,以及用什么字体吧。lz 可以把问题再具体一点。
    图片的话上面提到 pil 可以,截屏去拿也是个办法。
    终端的话因为是等宽的,且行宽可测所以推测行数也是可以的。
    justfortest
        10
    justfortest  
       2020-05-17 18:05:35 +08:00 via Android
    这是个复杂的问题
    jin7
        11
    jin7  
       2020-05-17 19:13:23 +08:00
    用 pyqt5/pyside2 就行了 很容易计算宽度
    XIVN1987
        12
    XIVN1987  
       2020-05-17 21:56:35 +08:00   ❤️ 1
    In [11]: s = '空铁 WIFI'

    In [12]: [ord(c) for c in s]
    Out[12]: [31354, 38081, 87, 73, 70, 73]

    In [13]: [1 if ord(c) < 0x80 else 2 for c in s]
    Out[13]: [2, 2, 1, 1, 1, 1]

    In [14]: sum([1 if ord(c) < 0x80 else 2 for c in s])
    Out[14]: 8
    lithbitren
        13
    lithbitren  
       2020-05-17 22:06:14 +08:00
    全角和半角符号的编码范围不是连续的,一个比较符的实现可能还是有 bug 的。
    Kisesy
        14
    Kisesy  
       2020-05-17 22:12:58 +08:00
    if unicodedata.east_asian_width(char) in ('F', 'W'):
    width = width + 2
    else:
    width = width + 1
    XiaoxiaoPu
        15
    XiaoxiaoPu  
       2020-05-17 22:28:12 +08:00
    有个现成的库,用了很久了 wcwidth
    aihimmel
        16
    aihimmel  
       2020-05-17 22:44:15 +08:00 via Android
    不要简单推定字符宽度
    "لا"
    上面这个是两个字符但是打印出来只有 1 的宽度,确定宽度最好还是渲染出来再取宽度
    songdg
        17
    songdg  
    OP
       2020-05-19 09:17:02 +08:00
    @codehz 谢谢,有必要还是要试一下。
    songdg
        18
    songdg  
    OP
       2020-05-19 09:18:43 +08:00
    @JCZ2MkKb5S8ZX9pq 谢谢,基本上解决了我的问题。
    songdg
        19
    songdg  
    OP
       2020-05-19 09:20:10 +08:00
    @Kisesy 谢谢帮助。
    songdg
        20
    songdg  
    OP
       2020-05-19 09:21:45 +08:00
    @XIVN1987 谢谢帮助。
    HashV2
        21
    HashV2  
       2020-05-20 17:54:26 +08:00
    @JCZ2MkKb5S8ZX9pq 哈哈哈哈 我用的也是这个,但确实不太优雅哈~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1152 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 18:11 · PVG 02:11 · LAX 10:11 · JFK 13:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.