Hatena::ブログ(Diary)

_dog(underdog)

2009-02-26

RubyとPythonで全角文字を半角文字2文字として数える

| 00:14

Rubyで左詰めを行うためにString#ljustを使ったが、文字列に全角文字や半角カナが混じると、予想していた空白の数に調整されなかった。そのためASCII文字と半角カナを判定して全角文字の数を数えてみた。ASCII文字と半角カナ以外の半角文字は考慮されていない。

Pythonでは、unicodedata.east_asian_widthを使用して全角と半角の文字を判別できるようだ。

追記:その2にて、RubyでもUnicodeのEast Asian Widthの定義を参照できるように修正した。ついでに右寄せと中央寄せも追加した。

Ruby 1.8.6

# 左寄せ
def ljust_kana(str, size, pad = " ")
    space = size - width_kana(str)
    if space > 0
        str += pad * space
    end
    return str
end

# 幅(半角基準)
def width_kana(str)
    all = str.scan(/./u).size       # 全文字数
    zenkaku = count_zen(str)        # 全角文字数
    hankaku = all - zenkaku     # 半角文字数
    
    return zenkaku * 2 + hankaku
end

# 全角文字数(不完全)
def  count_zen(str)
    all = str.scan(/./u).size       # 全文字数
    ascii = str.scan(/[ -~]/u).size     # ASCII文字数
    kana = str.scan(/[。-゚]/u).size      # 半角かな文字数
    
    return all - (ascii + kana)
end

# main
puts ljust_kana("日本語", 20) + "|"
puts ljust_kana("ニホンゴ", 20) + "|"
puts ljust_kana("nihongo", 20) + "|"
puts ljust_kana("niホン語", 20) + "|"

Python 2.5.1

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

import unicodedata

# 左寄せ
def ljust_kana(str, size, pad = " "):
    space = size - width_kana(str)
    if space > 0:
        str += pad * space
    return str
    
# 幅(半角基準)
def width_kana(str):
    all = len(str)      # 全文字数
    zenkaku = count_zen(str)        # 全角文字数
    hankaku = all - zenkaku     # 半角文字数
    
    return zenkaku * 2 + hankaku

# 全角文字数
def  count_zen(str):
    n = 0
    for c in str:
        wide_chars = u"WFA"
        eaw = unicodedata.east_asian_width(c)
        if wide_chars.find(eaw) > -1:
            n += 1
    return n
    
# main
if __name__ == "__main__":
    print ljust_kana(u"日本語", 20) + "|"
    print ljust_kana(u"ニホンゴ", 20) + "|"
    print ljust_kana(u"nihongo", 20) + "|"
    print ljust_kana(u"niホン語", 20) + "|"

結果

日本語              |
ニホンゴ               |
nihongo             |
niホン語              |

実行環境 Mac OSX 10.5.6 Leopard

Connection: close