読者です 読者をやめる 読者になる 読者になる

のんびり猫プログラマの日常

プログラムのことを書くかもしれない?

 

【JavaScript & HTML5 】文字コードに関係なくテキストファイルを正しく読み込む

JavaScript HTML5

f:id:catprogram:20150423171003j:plain

ブラウザ上で編集する「Webテキストエディタ」を作るという案件がありまして。
まず【既存のテキストファイルを読み込む】というところで引っかかったので覚書しとく。

テキストファイルといっても、文字コードがshift-jisだけならまだいいんだけど、
中にはUTF-8だったりEUCだったり、UTF-16とかもうね・・・
そういう様々な文字コードのファイルでも、正しく読み込んで表示しなくては
お話にならないのだ。

そこでググりながら作ったよ、もう。

1 File APIを使ってみる

HTML5になって、ローカルファイルを手軽に扱えるようになったね。
そう、File APIっていうのを使ってみようよ。

www.html5rocks.com

このページに書いてある、ファイル読み込み時のオプション。
これが大切です。以下、そのまま引用。

File 参照を取得したら、FileReader オブジェクトをインスタンス化してコンテンツをメモリに読み取ります。読み込みが終了すると、リーダーの onload イベントが開始され、result 属性を使用してファイル データにアクセスできるようになります。 
FileReader にはファイルを非同期で読み込むためのオプションが 4 つあります:

FileReader.readAsBinaryString(Blob|File)
result プロパティにはファイル/ブロブ データがバイナリ文字列として格納されます。各バイトは、0~255 の範囲の整数で表されます。

FileReader.readAsText(Blob|File, opt_encoding)
result プロパティにはファイル/ブロブ データがテキスト文字列として格納されます。デフォルトでは、この文字列は「UTF-8」としてデコードされます。オプションのエンコード パラメータを使用すると、他の形式を指定できます。

FileReader.readAsDataURL(Blob|File)
result プロパティにはデータ URL としてエンコードされたファイル/ブロブ データが格納されます。

FileReader.readAsArrayBuffer(Blob|File)
result プロパティには、ファイル/ブロブ データが ArrayBuffer オブジェクトとして格納されます。

今回はテキストファイルなんで、FileReader.readAsText を使えばいいじゃん!
UTF-8ならそのまんまでいいし、shift-jisなら、パラメータに
 FileReader.readAsText(fileオブジェクト, 'shift-jis');
と設定すれば読み込めそうだ。
しかし、文字コードの判定はいつやるの?読み込んだあとだよね・・・もしかして。
読み込もうとする命令に文字コードを指定するなんて、透視能力でもない限りできない。

甘い考えは脆くも崩れ去ったのだった・・・

2 バイナリで読み込んで変換かけるしかない

File AIPの FileReader.readAsArrayBufferでファイルを読み込んで、
ArrayBufferオブジェクトとして内容を受け取るのだ。
これで、ファイルの中身をバイナリで扱えることになる。

3 文字コードを判定して変換をかける

こういうライブラリを作ってくれる人がいるなんて、ホント神!

JavaScriptで文字コード変換ライブラリ作ってみた | 圧縮電子どうのこうの

神コード変換ライブラリ、encoding.jsをソースにかませてみよう。

 得体のしれない文字コード
      ↓
 とにかく何でもUNICODEに変換する (encoding.jsのconvert関数を使う)
      ↓
 文字列(string)に変換する(encoding.jsのcodeToSting関数を使う)

という処理を作る。

4 読み込みボタンを作る

普通に input type="file" を使ってもいいんだけど、
ブラウザによって形状が全く違うんだよ。
そこでボタンを新たに作ってみることにした。

まず見た目が普通のボタンを作るよ。

<button class="filebtn-show">読み込むボタン</button>

見えるボタンの裏に input tyle="file" を搭載した隠しボタンを作るよ

<input type="file" class="filebtn-hide" accept=".txt">

accept=".txt" で、拡張子が"txt"のファイルを選択表示すると親切。

隠しボタンは、cssで非表示にするなり透明にするなりして
とにかく見えないようにしておこう。

あとは、CSSで2つのボタンをうまーく重ねるか、
見えるボタンをClickしたら隠しボタンをClickするようにスクリプトを書くか。
どちらかお好きな方やってください。(私はスクリプト書いた)

CSSで重ねるのはIEでハマるらしいので、
スクリプト書ける人はそっちの方が手軽。

$('.filebtn-show').on('click', function(e){	
  $('.filebtn-hide').click();
});

5 完成

テキストファイルの改行をHTMLの改行(brタグ)にreplaceするなど
一手間加えて、完成。

ローカルのテキストファイルを読み込ませてみてにゃ。
サーバーにUPされるわけじゃないから、警戒しなくても大丈夫。
あくまでブラウザの中だけのお・は・な・し だよん。

See the Pen File API Test by catprogram (@catprogram) on CodePen.

ファイルの中身は文字化けしてないだろうか?
shift-jis, utf-8, utf-16, eucは確認済み。

滅多に使わない特殊な文字コードについては変換無理っぽいにゃ。
まぁ、実用に耐えうるということでこんな感じです、いじょ。