翻訳会社さんが英中韓に翻訳してくれたPHPのビュー部分のソースコードにBOMが付いていました。BOM というのは byte order mark の略で、ユニコードで記述されたファイルのエンディアンを識別するための目印です。これがファイルの先頭に付いているものをBOMあり、付いていないものをBOMなしと呼びます。

普段はBOMの有無など気にすることはないのですが、このビューファイルを使うと、画面上に不可解な空白が発生して、レイアウトが多少崩れるのです。原因を追ううちに、BOMを削ると正常に表示できることがわかりました。

調べてみると、PHP と BOM との相性はよくありません。例えば、header() や session_start() 関数を使う場合、BOMありのPHPファイルだと、HTTP のヘッダ部分が出力される前にBOMが出力されます。ヘッダ以外のものを出力した後にヘッダを出力することはHTTP上できないので、エラーになります。

BOMそのものは U+FEFF のユニコードキャラクタです。UTF-8の場合、ファイルの先頭3バイトが 0xEF, 0xBB, 0xBF にエンコーディングされます。

では、これをどう取り除くか。

$ sed -e '1s/^\xef\xbb\xbf//' text.txt

このsed版が一番短くて美しいでしょうか。

$ awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' text.txt

今回はこれを使いました。NRは行番号ですね。

$ tail --bytes=+4 text.txt

強制的に先頭3バイトを取り除くので、確実にBOMが付いていることがわかっているUTF-8ファイルのみ利用可能です。

$ ruby -e 'data = File.read(ARGV.first).sub(/\A\xef\xbb\xbf/,""); File.open(ARGV.first, "w") { |f| f.write data }' /path/to/file

指定したファイルをそのまま変換可能なことがウリです。が、こんな長いコード、打ちたくありません。

参考 http://www.linuxask.com/questions/how-to-remove-bom-from-utf-8 http://www.linuxask.com/questions/how-to-remove-bom-from-utf-8-using-sed