since 2011-04-20
http://docs.python.jp/2.7/library/unicodedata.html
Unicode を理解すると何をやってるのかわかってくる。。
Unicode HOWTO http://docs.python.jp/2/howto/unicode.html
http://tama-san.com/old/document06.html
全角文字を半角文字に正規化できる:
>>> import unicodedata >>> unicodedata.normalize('NFKC', u'100') u'100' >>> unicodedata.normalize('NFKC', u'.') u'.' >>> unicodedata.normalize('NFKC', u'・') u'\u30fb' >>> unicodedata.normalize('NFKC', u'、') u'\u3001' >>> unicodedata.normalize('NFKC', u'A') u'A' >>> unicodedata.normalize('NFKC', u'~') u'~'
一般に「チルダ」「波ダッシュ」のような文字:
>>> '%04x' % ord(u'~') '007e' >>> unichr(0x301c) u'\u301c' >>> '%04x' % ord(u'~') 'ff5e'
301c は正規化で変換されない:
>>> '%04x' % ord(unicodedata.normalize('NFKC', unichr(0x007e))) '007e' >>> '%04x' % ord(unicodedata.normalize('NFKC', unichr(0x301c))) '301c' >>> '%04x' % ord(unicodedata.normalize('NFKC', unichr(0xff5e))) '007e'
ちなみにコマンドプロンプトで下記を実行すると 003f が出てくるが、文字変換に失敗して '?' になったらしい:
>>> '%04x' % ord(u'〜') '003f'
エンマークは全角¥(0xffe5)を正規化するとバックスラッシュ(0x005c)ではなく Unicode の円記号(0x00a5)に変換される:
>>> '%04x' % ord(u'¥') 'ffe5' >>> '%04x' % ord(u'\\') '005c' >>> unichr(0x00a5) u'\xa5' >>> '%04x' % ord(unicodedata.normalize('NFKC', unichr(0x00a5))) '00a5' >>> '%04x' % ord(unicodedata.normalize('NFKC', unichr(0x005c))) '005c' >>> '%04x' % ord(unicodedata.normalize('NFKC', unichr(0xffe5))) '00a5'
全角バックスラッシュの正規化:
>>> '%04x' % ord(u'\') 'ff3c' >>> '%04x' % ord(unicodedata.normalize('NFKC', u'\')) '005c'
全角オーバーライン(?)を正規化すると「空白」と COMBINING MACRON の2文字になる:
>>> '%04x' % ord(u' ̄') 'ffe3' >>> unicodedata.normalize('NFKC', u' ̄') u' \u0304'
NFKC (composed) でもNFKD (decomposed) でも同じ結果になる:
>>> '%04x' % ord(unicodedata.normalize('NFKC', u' ̄')[0]) '0020' >>> '%04x' % ord(unicodedata.normalize('NFKC', u' ̄')[1]) '0304' >>> '%04x' % ord(unicodedata.normalize('NFKD', u' ̄')[0]) '0020' >>> '%04x' % ord(unicodedata.normalize('NFKD', u' ̄')[1]) '0304'
NFKC と NFC などの違いをみる:
>>> unicodedata.normalize('NFC', u'①') u'\u2460' >>> unicodedata.normalize('NFC', u'Ⅱ') u'\u2161' >>> unicodedata.normalize('NFD', u'①') u'\u2460' >>> unicodedata.normalize('NFD', u'Ⅱ') u'\u2161' >>> unicodedata.normalize('NFKC', u'①') u'1' >>> unicodedata.normalize('NFKC', u'Ⅱ') u'II' >>> unicodedata.normalize('NFKD', u'①') u'1' >>> unicodedata.normalize('NFKD', u'Ⅱ') u'II'
ちょっと脱線するがサロゲートペアの実験。
𦙾 d859de7e [ケイ] ケイコツノ ケイ:ニクヅキニ マタノシタ ツチ
出力するとコードポイント(32ビット)が得られるが、文字の長さは2文字になる:
>>> u'\ud859\ude7e' u'\U0002667e' >>> u'\ud859\ude7e'[0] u'\ud859' >>> u'\ud859\ude7e'[1] u'\ude7e'
ちなみにUTF-8では4バイトで表現される:
>>> len(u'\ud859\ude7e'.encode('utf-8')) 4
normalize の影響はない(NFC, NFD, NFKD でも同じ):
>>> unicodedata.normalize('NFKC', u'\ud859\ude7e') u'\U0002667e'