So-net無料ブログ作成

BOMに悩む [プログラム三昧]このエントリーを含むはてなブックマーク#

BOMって、ご存知でしょうか。 電子工作界隈であれば、 "Bill Of Materials" (部品表)なのですが、プログラマ界隈では、 "Byte Order Mark" (バイト順のしるし)の略なのだそうです。

Pythonで日本語を扱いたい

Python という言語で日本語を扱いたい場合、 Python 自身が内部でユニコードを使っていることから、すんなり使えると考えていました。 ところが、実際に使ってみると、 "UTF-8" で書いたはずのファイルが読み込めないという事態に陥ってしまいます。

どうも、ファイルの最初の3バイトに余計なデータが入っているようなのです。

0xef, 0xbb, 0xbf

これは、 Microsoft の Notepad (日本語ではメモ帳)でファイルの先頭に追加される記号です。 これが "Byte Order Mark" (BOM) と呼ばれています。

Python は、BOMを認めていない

Microsoft に偏った情報によると、 BOM の入ったファイルを UTF-8 と呼び、入っていないファイルを UTF-8N と呼ぶ宗派もあるようです。 ところが、 Python 的には、 UTF-8 エンコードというのは、あくまでも BOM の無いファイルを指すのであって、 BOM が入るようなものは UTF-8 とは認めていません。 そのため、 PythonBOM 付きのファイルを読ませようとすると、「ユニコードでは無い文字があるぞ。」と言って受け付けてくれません。

UnicodeEncodeError: 'cp932' codec can't encode character u'\ufeff' in position 0: illegal multibyte sequence

このメッセージでは、 "cp932" に問題があるように見えますが、問題は、 "cp932" では表現できない BOM にあるのです。

とはいえ、抜け道もある

まあ、突っ張っているだけでは、解決しないので、抜け道も用意されています。 それは、 "utf-8-sig" という呪文のようなエンコーディングを使うことです。 このエンコーディングでは、邪魔な BOM を取り除いてファイルを読み込んでくれます。 Notepad で書いた "UTF-8" ファイルを "MS漢字" ファイルに変換するプログラムは、こんな風になります。

fi=codecs.getreader('utf-8-sig')(open('in.txt','r'))
fo=codecs.getwriter('cp932')(open('out.txt','w'))
for line in fi.readlines():
  fo.write(line)
fo.close()
fi.close()

これで、すっきりしました。

参考文献

8.8.2. Encodings and Unicode
Python のオンラインドキュメントです。 Python は、内部処理こそユニコードを使っていますが、外部ファイルなどとのインターフェイスは、ユニコードばかりとは限りません。 そこで、考えられたのが、エンコーディングという考え方です。 これで、どんな文字コードにも対応できるはずなのですが、反面、エンコーディングの認識に失敗すると、文字化けとなって現れてしまいます。

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。