Python計算字符寬度的方法
本文實(shí)例講述了Python計算字符寬度的方法。分享給大家供大家參考,具體如下:
最近在用python寫一個CLI小程序,其中涉及到計算字符寬度,目標(biāo)是以友好的方式將一個長字符串截取為等寬的片段。
對于unicode字符,python的len函數(shù)可以準(zhǔn)確的計算其中所包含的字符個數(shù),但是個數(shù)并不代表寬度,如:
>>>len(u'你好a') 3
因此無法簡單的使用這種方式來計算寬度。
GBK decode
首先我想到GBK編碼,00–7F范圍內(nèi)的字符是一字節(jié)編碼,其余是雙字節(jié)編碼,正好與字符的寬度大體一致,于是有了這樣的投機(jī)取巧的辦法(假設(shè)取8個寬度):
>>> a = u'hello你好' >>> b=a.encode('gbk') >>> try: ... print b[:8].decode('gbk') ... except: ... print b[: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(xiàn)/H/N/Na/W都能很明確的知道寬度,如果保守起見,將A視為寬度為2的話,則很容易給出單個字符的寬度:
>>> import unicodedata >>> def chr_width(c): ... if (unicodedata.east_asian_width(c) in ('F','W','A')): ... return 2 ... else: ... return 1 >>> 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)確,讓我大為驚訝,于是翻開它的源碼一探究竟,文本寬度計算方面其核心代碼如下:
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), ] def get_width( o ): """Return the screen column width for unicode ordinal o.""" global widths if o == 0xe or o == 0xf: return 0 for num, wid in widths: if o <= num: return wid return 1
如代碼所示,首先根據(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 源碼。
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python圖片操作技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python Socket編程技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門與進(jìn)階經(jīng)典教程》及《Python文件與目錄操作技巧匯總》
希望本文所述對大家Python程序設(shè)計有所幫助。
- Python使用gensim計算文檔相似性
- Python實(shí)現(xiàn)計算最小編輯距離
- 詳解Python編程中基本的數(shù)學(xué)計算使用
- 基于python的Tkinter實(shí)現(xiàn)一個簡易計算器
- python利用datetime模塊計算時間差
- python實(shí)現(xiàn)計算倒數(shù)的方法
- python計算圓周率pi的方法
- python計算一個序列的平均值的方法
- Python計算一個文件里字?jǐn)?shù)的方法
- Python 字符串操作方法大全
- python分割和拼接字符串
- Python字符轉(zhuǎn)換
- Python 匹配任意字符(包括換行符)的正則表達(dá)式寫法
相關(guān)文章
對Django中的權(quán)限和分組管理實(shí)例講解
今天小編就為大家分享一篇對Django中的權(quán)限和分組管理實(shí)例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08利用python實(shí)現(xiàn)短信和電話提醒功能的例子
今天小編就為大家分享一篇利用python實(shí)現(xiàn)短信和電話提醒功能的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08Python基于字典實(shí)現(xiàn)switch case函數(shù)調(diào)用
這篇文章主要介紹了Python基于字典實(shí)現(xiàn)switch case函數(shù)調(diào)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07Python連接es筆記之創(chuàng)建和刪除操作示例詳解
這篇文章主要為大家介紹了Python連接es筆記之創(chuàng)建和刪除操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-0512個Pandas/NumPy中的加速函數(shù)使用總結(jié)
在本文中,數(shù)據(jù)和分析工程師?Kunal?Dhariwal?為我們介紹了?12?種?Numpy?和?Pandas?函數(shù),這些高效的函數(shù)會令數(shù)據(jù)分析更為容易、便捷2022-09-0910種檢測Python程序運(yùn)行時間、CPU和內(nèi)存占用的方法
這篇文章主要介紹了10種檢測Python程序運(yùn)行時間、CPU和內(nèi)存占用的方法,包括利用Python裝飾器或是外部的Unix Shell命令等,需要的朋友可以參考下2015-04-04python Hypothesis生成和執(zhí)行大量的測試用例
Hypothesis是一個基于屬性的測試(property-based testing)庫,它能夠幫助我們生成和執(zhí)行大量的測試用例,與傳統(tǒng)的單元測試相比,屬性測試更加靈活和全面,能夠發(fā)現(xiàn)更多的邊界情況和潛在的錯誤2024-01-01