2003年03月30日

[misc] 萌え萌えうにっくす

明日発売だと思っていたら、もう書店に並んでいるようで。しかも、amazonなどでは注文殺到で売り切れだそうで。ほげほげ。

[comp:python] 日本語文字コード変換

python で EUC<->SJIS<->UTF-8 変換などを行おうと考えると大まかに選択肢は2つあります。独立した変換ライブラリの kconv と python1.6 から加わった Unicode サポートに準じる JapaneseCodecs です。

最近の python には unicode 型が存在し、u'Unicode String' で簡単に作成することができます。標準では普通の文字列型を unicode 型に変換するときには元の文字コードが ascii であることが仮定され、0x80 以上の文字コードが存在するとエラーになりますが、特定の文字コードに対する Codec をインストールすると任意の文字コードを扱うことが可能になります。JapaneseCodecs をインストールした上で u = unicode('うにこーど文字列', 'japanese.euc-jp') などと指定すれば EUC で記述されたソースコードで unicode 型を作成することができるわけです。同様に u.encode('japanese.shift_jis') とすれば、unicode 型を文字列型に変換し、その過程で shift_jis に変換することが可能になります。このように JapaneseCodecs は python 処理系と密接に関わる形で作用するため綺麗ですが、特定の文字コードを unicode へ encode/decode することのみを目的として作られているため、文字コードの自動認識や全角半角変換など+αの機能が全くありません。

一方、kconv は jcode.pl と同じような立場の文字コード変換ライブラリですので、toEUC = kconv.Kconv(kconv.EUC); toEUC(some_form_param) で文字コードを自動認識して EUC へ変換、なんてことができます。ただ、文字列型から文字列型への変換ですので python 組み込みの unicode 型と一緒に使おうとしたときに様々な混乱を生むことになります。

で、実際に起こった混乱の結果。

from SOAPpy import SOAP
import kconv
toU = kconv.Kconv(kconv.UTF8, kconv.EUC).convert
toE = kconv.Kconv(kconv.EUC, kconv.UTF8).convert
server = SOAP.SOAPProxy(SoapEndpointURL)
result = server.doAuthorSearch(
    0,                                  # start
    10,                                 # max
    unicode(toU('今野'), 'UTF-8'),      # authorName
    unicode(toU('コンノ'), 'UTF-8')     # authorNameKana
)
print result.resultCount
for part in result.resultElements:
    print toE(part.authorNameKana.encode('UTF-8'))

SOAPpy は文字列型を渡すと unicode 型へ内部で自動的に変換するらしく、おかしな事になります。JapaneseCodecs を使わないで解決するためにはあらかじめ unicode 型にしてからメソッドへ渡してやらないといけません。そんなわけで、unicode(s, 'UTF-8') やら encode('UTF-8') やらという虚しい無変換作業が挟まっているわけです……。ちなみに JapaneseCodecs を使用し、なおかつ site.py で default encoding を 'japanese.euc-jp' に指定していた場合は以下のようにとてもすっきりします。

from SOAPpy import SOAP
server = SOAP.SOAPProxy(SoapEndpointURL)
result = server.doAuthorSearch(
    0,           # start
    10,          # max
    '今野',      # authorName
    'コンノ'     # authorNameKana
)
print result.resultCount
for part in result.resultElements:
    print part.authorNameKana

SOAPpy 内部で unicode(...) された時に自動的に euc-jp -> unicode へ変換され、print で表示するときに自動的に unicode -> euc-jp の変換が起こったため、外見的には unicode を使用している痕跡すら見えません。システムに統合された Codec の勝利、という感じです。