Pythonで全角文字を含む文字列の幅を取得する

ただし、あくまで半角文字が1で全角文字が2の環境の場合です。

 

1 エンコーディングの記載

あまりお勧めしませんが、ソースコードに全角文字列を埋め込む場合、ファイル先頭にUTF-8でエンコーディングされている旨を記載してpythonインタプリタに認識させる必要があります。

# -*- coding: utf-8 -*-

今回は全角文字列の幅を取得するコードを扱う為、ソースコードの先頭にエンコーディングを記載します。

2 全角文字の扱い

uをつけた場合はUTF-8文字列として扱われます。

>>> print(len(u'こんにちは、world'))
11

uをつけなかった場合はバイト列として扱われます(UTF-8の場合、日本語の文字は3Byteで表現されます)。

>>> print(len('こんにちは、world'))
23

バイト列を探索してutf-8の文字を判定すれば幅を割り出せますが、すでにunicodedataという便利なライブラリがその処理を実行してくれています。

3 unicodedata.east_asian_widthで文字幅取得

unicodedata.east_asian_widthメソッドで文字の種類を判別します。Asciiコードは'Na'、全角文字は'W'、半角カナは'H'が返ってきます。これを利用し、文字幅と文字列幅を以下のように算出します。

# -*- coding: utf-8 -*-

import unicodedata


def get_char_width(c):
    data = unicodedata.east_asian_width(c)
    if data == 'Na' or data == 'H':
        return 1
    return 2


def get_string_width(string):
    width = 0
    for c in string:
        width += get_char_width(c)
    return width


string = u'コんにちは、world'
print('%s' % string)
print('-' * get_string_width(string))
print('len(string) = %d' % len(string))
print('get_string_width(string) = %d' % get_string_width(string))

'コんにちは、world'という文字列の文字数は11となります。'コ'は1、'んにちは、'は10、'w'は2、'orld'は4の幅と計算されます。

コんにちは、world
-----------------
len(string) = 11
get_string_width(string) = 17

*上のコードに以下のnormalize_stringという関数を追加して、幅の最大値を超えない文字列のインデックス値を探索します。

def normalize_string(string, max_width):
    index = 0
    sum_width = 0
    while index < len(string):
        c_width = get_char_width(string[index])
        if sum_width + c_width > max_width:
            break
        sum_width += c_width
        index += 1
    return string[0:index]

...

print('normalize_string(string, 10) = %s' % normalize_string(string, 10))
print('normalize_string(string, 11) = %s' % normalize_string(string, 11))
print('normalize_string(string, 12) = %s' % normalize_string(string, 12))
print('normalize_string(string, 13) = %s' % normalize_string(string, 13))
print('normalize_string(string, 14) = %s' % normalize_string(string, 14))

実行結果は以下のようになりました。

normalize_string(string, 10) = コんにちは
normalize_string(string, 11) = コんにちは、
normalize_string(string, 12) = コんにちは、
normalize_string(string, 13) = コんにちは、w
normalize_string(string, 14) = コんにちは、wo