Python bite: 文字集合非対応文字の変換
Tagged:  •  

Python 自体に咬まれたわけではないですが、 Python での実装中の話なので Python bite の括りで書きます。

入出力の文字集合体系(所謂「文字コード」) が一致している場合は問題無いのですが、 これらが一致していない場合、 出力文字コードが対応していない文字が入力に含まれていると咬まれます

例えば Unicode の入力をベースに Shift_JIS の出力を生成するような場合、 '\uFF5E'(所謂「全角チルダ」)のような文字が使用されていると、 変換に失敗します。

% python
> import codecs
> import sys
> sys.stdout = codecs.getwriter('shift_jis')(sys.stdout)
> print u'\uff5e'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeEncodeError: 'shift_jis' codec can't encode 
    character u'\uff5e' in position 0: 
    illegal multibyte sequence
非対応文字の変換失敗

これは文字集合定義上の問題なので、 プログラムレベルでは根本的な解決はできません。

出来ることと言えば、 以下のような変換処理をはさむことで、 非対応文字を別な文字に変換してやることぐらいです (この変換テーブルでは不十分かもしれませんのでご注意ください) 。

convert_tuples = [
 (u'\u00a6',u'\u007c'),#broken bar=>vertical bar
 (u'\u2014',u'\u2015'),#horizontal bar=>em dash
 (u'\u2225',u'\u2016'),#parallel to=>double vertical line
 (u'\uff0d',u'\u2212'),#minus sign=>fullwidth hyphen minus
 (u'\uff5e',u'\u301c'),#fullwidth tilde=>wave dash
 (u'\uffe0',u'\u00a2'),#fullwidth cent sign=>cent sign
 (u'\uffe1',u'\u00a3'),#fullwidth pound sign=>pound sign
 (u'\uffe2',u'\u00ac'),#fullwidth not sign=>not sign
]

def unsafe2safe(string):
    for unsafe, safe in convert_tuples:
        string = string.replace(unsafe, safe)
    return string
非対応文字の変換

Java の StringBuffer のような可変文字列を扱うクラスがある場合、 上記程度の変換テーブルサイズなら間違いなく 「対象文字列⇒変換テーブル」の入れ子構造にする (あるいはテーブル長と対象長の比較でループを切り替える )のですが、 Python では改変可能文字列クラスが無い (それともこういう場合は StringIO とかを使うのが一般的なのでしょうか? > Python ハッカー様)ため、 性能的にはちょっと嫌なループの組み方になっています。

なお、上記 unsafe2safe() を適用するオブジェクトは 「Unicode 文字列」オブジェクトである必要があるため、 適宜事前処理してやる必要があるかもしれません。