この記事の例では、Python で文字幅を計算する方法を説明します。参考のために皆さんと共有してください。詳細は次のとおりです:
私は現在、Python で小さな CLI プログラムを作成しています。これには、文字幅の計算が含まれます。その目的は、長い文字列をわかりやすい方法で同じ幅の断片に分割することです。
Unicode 文字の場合、Python の len 関数はその文字に含まれる文字数を正確に計算できますが、その数値は幅を表しません。
>>>len(u'你好a') 3
したがって、この方法で単純に幅を計算することはできません。
GBK デコード
まずGBKエンコードを考えたのですが、00~7Fまでの文字は半角エンコード、それ以外は文字の幅とほぼ一致する全角エンコードということになりました。この便宜的な方法を使用します (幅 8 を想定):
>>> a = u'hello你好' >>> b=a.encode('gbk') >>> try: ... print b[:8].decode('gbk') ... except: ... print b[:7].decode('gbk') ... hello你
コードに示されているように、まず Unicode 文字列を GBK にエンコードし、次に 8 バイトの幅をインターセプトし、GBK を使用してデコードしようとします。デコードが失敗した場合は、1 つ少ない幅をインターセプトし、7 バイトをインターセプトして GBK デコードを使用します。
問題は当初は解決されましたが、欠点は明らかです。第一に、コードは洗練されておらず、試行錯誤的に実行されます。第二に、GBK が表現できる文字は限られており、GBK エンコーディング以外の多数の文字をサポートできません。
East_Asian_Width
長い間さまよった後、Unicode 文字データベース標準には 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 として扱う場合、単一の幅を与えるのは簡単です。文字:
>>> 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
現在は要件を満たしているように見えますが、実際に使用すると、属性 A を持つ文字が見つかることは珍しくありません。最も典型的なのは中国語の二重引用符です:
>>> chr_width(u'”') 2
ほとんどの固定幅フォントでは、中国語の二重引用符は 1 桁の幅しかありません。複数の中国語の二重引用符が並んでいる場合、誤判定の幅が積み重なることで、インターセプト効果が大幅に減少することは間違いありません。最良のアプローチ。
urwid の解決策
urwid は成熟した Python ターミナル UI ライブラリです。テキスト コンテンツを表示するために、curses に基づいた HTML のようなコントロールをパッケージ化しています。この分野で開発が必要な場合は、curses ライブラリを直接使用するのではなく、このライブラリを強くお勧めします。非常に便利なのは、Unicode のテキスト幅インターセプトが非常に正確であることです。非常に驚いたので、テキスト幅計算のコア コードは次のとおりです。
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コードに示すように、まず Unicode の公式 EastAsianWidth ドキュメントに従って文字幅範囲テーブルを整理し、次に Unicode コードを使用してテーブルを検索します。前の例を使用してテストします:
>>> get_width(ord(u'a')) 1 >>> get_width(ord(u'你')) 2 >>> get_width(ord(u'”')) 1これは完全に正確で、実際のアプリケーションでは比較的うまく機能します。詳細については、urwid の old_str_util.py ソース コードを参照してください。
Python 関連のコンテンツにさらに興味がある読者は、このサイトの特別トピックをチェックしてください: 「Python 画像操作スキルの概要」、「Python データ構造とアルゴリズムのチュートリアル」、「Python ソケット プログラミング スキルの概要」、「 Python 関数の使用スキルのまとめ」、「Python の文字列操作のスキルのまとめ」、「Python 入門と上級の古典的なチュートリアル」、および「Python ファイルとディレクトリの操作のスキルのまとめ」
この記事が Python プログラミングのすべての人に役立つことを願っています。