テキストファイルの文字コードは中身で決まる。らしい。


今まで文字コードって、ファイルのメタ情報的な領域にファイルごとに定義されていて、それを元にテキストエディタなりがそのファイルを開くときに文字のバイト列をうまく変換するのかと思っていたのですが、どうやらそういう感じではないらしい、ということを知ったのでまとめてみます。

ざっくりファイルシステムについて

そもそもコンピューターはファイルをどうやって管理しているのか、というファイルシステムの話なのですが、こちらの知恵袋 がとても勉強になりました。

ざっくり言うと、ファイルの内容はディスク上の一定のサイズで区切られた領域に記録されていて、管理領域にその場所やファイル名、パーミッション情報などが記録されている、ということらしいです。

文字コード情報は?

では文字コードは「管理領域」に記録されているのでしょうか。
というわけで実験してみました。

$ echo あ >> a.txt
$ nkf -g a.txt
UTF-8

単純に「あ」と書かれたファイルを作ると、それは UTF-8 と認識されるようです。(PCの設定によって変わりそうです)

次に、比較用に EUC-JP のファイルを作ります。

$ nkf -e a.txt > e.txt
$ nkf -g e.txt
EUC-JP

a.txtの内容をnkf -eでEUC-JPに変換し、それをe.txtとして保存します。
e.txtはEUC-JPと認識されています。ここまでは想定通りですね。

では、a.txte.txtの内容を追記してみます。
もしファイルの管理領域に「このファイルはUTF-8である」という情報が保持されているのであれば、EUC-JP形式のバイト列が混ざろうがそれはUTF-8ファイルと認識されるはずです。

$ cat e.txt >> a.txt
$ nkf -g a.txt
BINARY

UTF-8でもなくEUC-JPでもなくBINARYと表示されました。もはや文字コードじゃないですね。。。
UTF-8だと解釈してもEUC-JPと解釈しても正常に読み取れない部分があるということで、もはやテキストデータではないと判断されて感じですね。

いずれにしても、内容次第で文字コードが変わるということは、文字コードはファイルの管理領域に記録されているのではなく、ファイルの内容自体から判定されていることがわかりました。

最後に、a.txtの一行目を削除して(つまりEUC-JPの行だけ残して)みます。

$ vi a.txt
# 一行目を削除

$ nkf -g a.txt
EUC-JP

EUC-JPになりました。
ファイルを編集しただけでコロコロ文字コードの判定が変わる、ということは、やはり文字コードはファイルの内容から判定されているだけだということがわかりますね。

まとめ

今までファイルの文字コードを変えるというと、nkf -eしたり秀丸で文字コードを変更して保存したりと、何となく変更して何となくちゃんと表示てきてOKとしていたのですが、実際にファイル自体にどんな変化が起きているのかを正確には把握できていませんでした。実際はファイル内の日本語部分のエンコーディングの形式を変えているだけということですね。

その他にも、ファイルの中身で文字コードが決まるということは、例えばHTMLで最初にファイルのエンコーディングを定義しておけば、その通りにブラウザが表示してくれる、という仕組みも何ら不思議ではないことが分かります。きっとブラウザはファイル内の文字列のバイト列が何の文字コードで表現されたバイト列なのかよりも、HTMLタグで定義された文字コードを優先する、というところでしょうか。

また、半角英数字しか含まれないファイルの文字コードがASCIIになるのもその通りですね。

$ echo a >> b.txt

$ nkf -g b.txt
ASCII

ファイルの文字コードの判定の仕組みの他にも、ファイルシステムの仕組みも簡単に知ることができたことも良い勉強になりました。