pythonで丁寧な文字コード変換

うちの研究室のサーバーがEUC-JPのために、python文字コードEUC-JPに設定しています。その方が、いちいち文字コードのことを考えずに済むからです。
ただ、pythonでは一般的にUTF-8を用いることを薦めているようで、EUC-JPだと何かと不都合も起きてきます。例えば、BeautifulSoupというモジュールは、パラメータとしてUTF-8の文字列を必要とします(EUC-JPだとエラー。Unicode型ならOK)。なので、最終的にはEUC-JPからUTF-8に変換しないといけないのですが、これが一筋縄でいかないことが多いのです。特に、インターネットから取ってくる文書データを変換するときは気をつけなければいけないようです(経験知)。

不特定の文字コードからUnicode型へ変換(丁寧に)

これは意外と楽なのです。というか、これができなければ、このデータはもう処理できないんじゃないでしょうか?それくらい、Unicode型は懐が深いです。多くのブログで紹介されていますが、ここでは文字コード判定して一括でuft-8に変換するPythonスクリプト — 清水川Webを拡張したプログラムを載せます。

def tounicode(data):
    f = lambda d, enc: d.decode(enc);
    codecs = ['shift_jis','utf-8','euc_jp','cp932',
              'euc_jis_2004','euc_jisx0213','iso2022_jp','iso2022_jp_1',
              'iso2022_jp_2','iso2022_jp_2004','iso2022_jp_3','iso2022_jp_ext',
              'shift_jis_2004','shift_jisx0213','utf_16','utf_16_be',
              'utf_16_le','utf_7','utf_8_sig'];

    for codec in codecs:
        try: return f(data, codec);
        except: continue;
    return None;

codecsに格納されているのは、日本語対応の文字コードです。「無駄なんじゃね?」と思われるかもしれませんが、意外と変な文字コードが使われていることがあるのです(経験知)。代表的なのは、shift-jis,utf-8,euc-jpなんだと思うので、これらは要素番号の若い方に入れておいた方がいいかもしれませんw

Unicode型からEUC-JPに変換(丁寧に)

この変換は普通にやると一筋縄でいかない可能性があります。Unicode型という懐の深い文字コード(?)からEUC-JPというちょっと好き嫌いがある文字コードに変換しようとすると、たまにEUC-JPが変換を拒むときがあります。普通、UnicodeからEUC-JPに変換するには

s = u'テスト';
s = s.encode('euc-jp');

もちろん、これは難なく変換できるのでしょうが、インターネット上から取得した何が書いてあるかわからない文書を変換するときに、その文書の文字を一気に変換しようとすることは危険な気がします。その文書の99%の文字が成功しても、1%が変換できなければ、その変換は失敗に終わるからです。ということで、こんなプログラムを作ってみました。

def toeuc(data):
    data1 = tounicode(data); # 上で紹介したUnicode変換メソッド
    data2 = '';
    for char in data1[:]:    # スライスで一文字ずつ調べる
        try:
            data2 += char.encode('euc-jp');
        except:
            pass;
    return data2;

pythonの文字型はリストのように扱うことが可能ですから、このようにして一文字ずつ地道にencodeしていくというプログラムを作ってみました。通常より時間がかかりそうですが、いたしかたないところです(><)

雑記・疑問

Unicode型は本当に懐が深いのかな? 深いとしたらどれくらい? すべての文字に対応できるのかな?

追記(9/16)

encode()には、errorsという引数があって、そこで変換エラーへの対処法を設定できるとのことです。つまり、わざわざメソッドを作らなくても、丁寧に変換ができるということです。我ながら、早とちりでした(><)
参考までに、引数errorsの紹介をします。

文字列 説明
strict 通常通り。エラーが起きたら例外を発生させる。
replace 変換できない文字は、?などに置き換える。例外は発生させない
ignore 変換できない文字は取り除く。例外は発生させない