python如何计算字符宽度_Python中计算字符宽度
轉(zhuǎn)載:http://likang.me/blog/2012/04/13/calculate-character-width-in-python/
最近在用python寫一個CLI小程序,其中涉及到計(jì)算字符寬度,目標(biāo)是以友好的方式將一個長字符串截取為等寬的片段。
對于unicode字符,python的len函數(shù)可以準(zhǔn)確的計(jì)算其中所包含的字符個數(shù),但是個數(shù)并不代表寬度,如:
>>>len(u'你好a')3
因此無法簡單的使用這種方式來計(jì)算寬度。
GBK decode
首先我想到GBK編碼,00–7F范圍內(nèi)的字符是一字節(jié)編碼,其余是雙字節(jié)編碼,正好與字符的寬度大體一致,于是有了這樣的投機(jī)取巧的辦法(假設(shè)取8個寬度):
>>>a=u'hello你好'>>>b=a.encode('gbk')>>>try:...printb[:8].decode('gbk')...except:...printb[:7].decode('gbk')...hello你
如代碼所示,首先將unicode的字符串進(jìn)行GBK編碼,然后截取8個字節(jié)的寬度后嘗試用GBK解碼,若解碼失敗,則少截取一個寬度,截取7個字節(jié)后使用GBK解碼。
雖然初步解決了問題,但是這樣做的硬傷很明顯。首先代碼不優(yōu)雅,以試錯的方式運(yùn)行;其次GBK所能表示的字符有限,對于大量GBK編碼以外的字符無法支持。
East_Asian_Width
徘徊很久之后,偶然發(fā)現(xiàn) Unicode Character Database標(biāo)準(zhǔn)中有East_Asian_Width 屬性,并有以下可能值:
# East_Asian_Width (ea)ea;A;Ambiguous不確定ea;F;Fullwidth全寬ea;H;Halfwidth半寬ea;N;Neutral中性ea;Na;Narrow窄ea;W;Wide寬
其中除A不確定外,F/H/N/Na/W都能很明確的知道寬度,如果保守起見,將A視為寬度為2的話,則很容易給出單個字符的寬度:
>>>importunicodedata>>>defchr_width(c):...if(unicodedata.east_asian_width(c)in('F','W','A')):...return2...else:...return1>>>chr_width(u'你')2>>>chr_width(u'a')1
到現(xiàn)在似乎已經(jīng)可以滿足要求了,但是實(shí)際使用中發(fā)現(xiàn)屬性為A的字符真不少見,最典型的就是中文的雙引號:
>>>chr_width(u'”')2
在大多數(shù)等寬字體中,中文雙引號都是只占一位寬的,如果一行里有多個中文雙引號,則累加的誤判寬度將會使截取效果大打折扣,無疑這也不是最好的辦法。
urwid的解決方案
urwid是一個成熟的python終端UI庫,它在curses的基礎(chǔ)之上包裝了類似HTML的控件用以顯示文本內(nèi)容,如果有這方面的開發(fā)需求,非常推薦此庫,比直接使用curses庫方便很多,非常棒的是它對unicode的文本寬度截取非常準(zhǔn)確,讓我大為驚訝,于是翻開它的源碼一探究竟,文本寬度計(jì)算方面其核心代碼如下:
widths=[(126,1),(159,0),(687,1),(710,0),(711,1),(727,0),(733,1),(879,0),(1154,1),(1161,0),(4347,1),(4447,2),(7467,1),(7521,0),(8369,1),(8426,0),(9000,1),(9002,2),(11021,1),(12350,2),(12351,1),(12438,2),(12442,0),(19893,2),(19967,1),(55203,2),(63743,1),(64106,2),(65039,1),(65059,0),(65131,2),(65279,1),(65376,2),(65500,1),(65510,2),(120831,1),(262141,2),(1114109,1),]defget_width(o):"""Return the screen column width for unicode ordinal o."""globalwidthsifo==0xeoro==0xf:return0fornum,widinwidths:ifo<=num:returnwidreturn1
如代碼所示,首先根據(jù)unicode的官方EastAsianWidth文檔整理出字符寬度的范圍表,然后使用unicode代碼查表。使用之前的例子測試:
>>>get_width(ord(u'a'))1>>>get_width(ord(u'你'))2>>>get_width(ord(u'”'))1
完全準(zhǔn)確,而且在實(shí)際應(yīng)用中的表現(xiàn)也比較好,是一個理想的解決方案,更多技巧請查閱urwid的old_str_util.py源碼。
總結(jié)
以上是生活随笔為你收集整理的python如何计算字符宽度_Python中计算字符宽度的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 孙权加智力还是武力
- 下一篇: 云听怎么跳过片头片尾(云平台基本概念)