LoginSignup
5
2

More than 5 years have passed since last update.

pythonで文字列の見た目幅の長さを調べる

Last updated at Posted at 2016-02-13

等幅フォントでの縦揃えがしたくて書いてみた

文字コードで全角判定をしてみる

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

def width(s):
    return sum([_width(c) for c in s.decode('utf-8')])

def _width(c):
    return 2 if _isMultiByte(c) else 1

def _isMultiByte(c):
    return ord(c) > 255

動作確認

assert 0 == width('')

assert 1 == width('a')
assert 1 == width('A')
assert 1 == width('ア')
assert 1 == width('-')
assert 1 == width('+')
assert 1 == width(' ')
assert 1 == width('\\')
assert 1 == width('\n')
assert 1 == width('\t')

assert 2 == width('aa')
assert 2 == width('AA')
assert 2 == width('が')
assert 2 == width('っ')
assert 2 == width('ぽ')
assert 2 == width('い')
assert 2 == width('!')
assert 2 == width('G')
assert 2 == width('ア')
assert 2 == width('○')
assert 2 == width('■')
assert 2 == width('、')
assert 2 == width('。')
assert 2 == width('‐')
assert 2 == width('ー')
assert 2 == width(' ')
assert 2 == width('\\\\')
assert 2 == width('\r\n')

assert 4 == width('YY')
assert 4 == width('0w0')
assert 4 == width('OK!')

だけおかしい...全角だと判定されている...

East Asian Widthという規定があるとのこと

_isMultiByteだけ修正

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

def width(s):
    return sum([_width(c) for c in s.decode('utf-8')])

def _width(c):
    return 2 if _isMultiByte(c) else 1

def _isMultiByte(c):
    import unicodedata
    return unicodedata.east_asian_width(c) in ['F', 'W', 'A']

今度は全部問題なし!
これで良さそうかな?

補足

想定しているのは標準入力とか

$ echo ほわ〜ぁ | python width.py
8
width.py
# -*- coding: utf-8 -*-

import sys
s = sys.stdin.readlines()[0].strip()

print width(s)

コマンドライン引数とかです

$ python width.py ほわ〜ぁ
8
width.py
# -*- coding: utf-8 -*-

import sys
s = sys.argv[1]

print width(s)

あと、ギリシャ文字とかアラビア文字とかは動作保証対象外です

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2