IE 限定・ローカルにある UTF-8 の HTML ファイルから Shift-JIS 形式のファイルを文字化けさせずに読み込む方法

この UTF-8 の HTML ファイルから、Shift-JIS のファイルを読み込んで、インラインに展開させたい。jQuery の load() みたいなことをしたい。

しかし、jQuery の ajax() やら get() やら load() やらは、いずれも UTF-8 のファイルを読み込むのがデフォルトになっているので、Shift-JIS のファイルを読もうとすると文字化けしてしまう。

そんなワケで、ローカルの HTML ファイルから他の HTML ファイルを読み込む jQuery のメソッドを試してみつつ、読み込む対象のファイルのエンコード指定と文字化けの関係を調べてみた。

長くなりそうなので先に結論を

呼び元が UTF-8 の HTML ファイルで、Shift-JIS の別ファイルを読み込みたい時は、Scripting.FileSystemObject を使って Shift-JIS のファイルを読み込み、ReadAll() などで拾った値を jQuery.html() の引数にでも与えてやれば、両ファイル間で文字コードが違っても文字化けせずに読み込める。

FileSystemObject が使えるのは ActiveXObject が使える IE11 だけで、かつローカルでしか使えないと思うので、「IE11 限定」「ローカルにある HTML ファイル限定」というワケ。

では、以下、順に試してみる。

呼び元の HTML ファイル

まずはテストするための、呼び元の HTML ファイルを作った。以下のような感じで、Shift-JIS の HTML と、UTF-8 の HTML とを、それぞれ4つの読み込み方で読み込もうとしている。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Load Local File</title>
    <style>

/* 適当にスタイル付けしとく~ */

* {
  margin:0;
  box-sizing:border-box;
  line-height:1.1;
}

body {
  width:100%;
  margin-top:1rem;
}

body > div {
  width:48.5%;
  padding:1rem;
}

section {
  height:5rem;
}

#sjis {
  float:left;
  margin-left:1%;
  border:1px solid #09f;
}

#utf8 {
  float:right;
  margin-right:1%;
  border:1px solid #f09;
}

h2, section {
  margin:1rem 0;
}

    </style>
    <!-- jQuery は適当に v1 系を読んでおく -->
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script>

// ・ShiftJIS.html
// ・UTF-8.html
// 2つの HTML ファイルをこの HTML と同階層に置いておく

// Firefox の「整形式になっていません。」エラー
// → $.ajax() と $.get() で、dataType に "html" を明記しないと発生する (IE・Chrome は dataType を省略しても動作する)

// Chrome の「Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.」
// → Chrome を起動するときに「--allow-file-access-from-files」オプションを与えて起動すると動くようになる

$(function() {
  
  $("#sjis-load").append($("<div>").load("ShiftJIS.html", function(data) {
    console.log("Shift-JIS Load : " + data);
  }));
  $.ajax({
    type: "GET",
    url: "ShiftJIS.html",
    dataType: "html",
    success: function(data) {
      console.log("Shift-JIS Ajax : " + data);
      $("#sjis-ajax").append($("<div>").html(data));
    },
    error: function() {
      console.log("Shift-JIS Ajax : Error");
    }
  });
  $.get("ShiftJIS.html", function(data) {
    console.log("Shift-JIS Get : " + data);
    $("#sjis-get").append($("<div>").html(data));
  }, "html");
  $("#sjis-fso").append($("<div>").html(loadFso("Shift-JIS", "ShiftJIS.html")));
  
  $("#utf8-load").append($("<div>").load("UTF-8.html", function(data) {
    console.log("UTF-8 Load : " + data);
  }));
  $.ajax({
    type: "GET",
    url: "UTF-8.html",
    dataType: "html",
    success: function(data) {
      console.log("UTF-8 Ajax : " + data);
      $("#utf8-ajax").append($("<div>").html(data));
    },
    error: function() {
      console.log("UTF-8 Ajax : Error");
    }
  });
  $.get("UTF-8.html", function(data) {
    console.log("UTF-8 Get : " + data);
    $("#utf8-get").append($("<div>").html(data));
  }, "html");
  $("#utf8-fso").append($("<div>").html(loadFso("UTF-8", "UTF-8.html")));
});

function loadFso(mode, fileName) {
  try {
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    // FileSystemObject の起点はデスクトップになるようなので、基本的に絶対パスでないと読み込めない
    // (起点は fso.GetFolder("."); で確認)
    var file = fso.OpenTextFile("C:/Test/" + fileName);
    var text = file.ReadAll();
    console.log(mode + " FSO [" + fileName + "] " + text);
    return text;
  }
  catch(e) {
    console.log(mode + " FSO [" + fileName + "] : Error " + e);
    return "Error : " + e;
  }
}

    </script>
  </head>
  <body>
    <div id="sjis">
      <h1>Shift-JIS</h1>
      <section id="sjis-load">
        <h2>jQuery Load</h2>
      </section>
      <section id="sjis-ajax">
        <h2>jQuery Ajax</h2>
      </section>
      <section id="sjis-get">
        <h2>jQuery Get</h2>
      </section>
      <section id="sjis-fso">
        <h2>File System Object</h2>
      </section>
    </div>
    <div id="utf8">
      <h1>UTF-8</h1>
      <section id="utf8-load">
        <h2>jQuery Load</h2>
      </section>
      <section id="utf8-ajax">
        <h2>jQuery Ajax</h2>
      </section>
      <section id="utf8-get">
        <h2>jQuery Get</h2>
      </section>
      <section id="utf8-fso">
        <h2>File System Object</h2>
      </section>
    </div>
  </body>
</html>

この HTML ページ自体は <meta charset="UTF-8"> と書いているとおり、UTF-8 でエンコーディングする前提。そのため、Shift-JIS でエンコーディングされている ShiftJIS.html を jQuery で読み込むと文字化けする。

しかし、FileSystemObjectShiftJIS.html を読み込み、その内容を

$("#sjis-fso").append($("<div>").html(loadFso("Shift-JIS", "ShiftJIS.html")));

このようにして HTML 内に展開すると、文字化けせずに表示させられる。

ブラウザごとに色々引っかかったポイントがあった。

結果の画面キャプチャ

順に表示結果を見てみる。

IE11

IE11 での結果

画面左下の「Shift-JIS」 : 「FileSystemObject」部分。UTF-8 の HTML ファイルであるにも関わらず、Shift-JIS の HTML ファイルを読み込んで文字化けせずに展開できている。それ以外の jQuery を使った方法では文字化けしてしまっている。

また、UTF-8 のファイルを FileSystemObject で読み込んでも文字化けしてしまうことから、有効なのは「UTF-8 の HTML ファイルで Shift-JIS の HTML ファイルを読み込む場合」のみ。また、FileSystemObject の性質上、サーバを介して使用することはないだろうから、ローカルの HTML ファイルでのみ使える技、ということになる。

Firefox

Firefox での結果

以降は同じソースを他のブラウザで見てみただけ。

Firefox でも Shift-JIS の HTML ファイルは文字化けしているほか、ActiveXObject が使えないので FileSystemObject も当然使えない。

Firefox は別の方法でローカルの HTML ファイルを読み書きできるみたいだけど、Components がもう使えない?らしく、うまくいかなかった。

Chrome

Chrome での結果

Chrome も Firefox と同様の表示。

Chrome でローカルファイルを操作するには File API が使えるらしい。試してない。

Edge

Edge での結果

Windows10 にしたことだし、Edge でも見てみた。Edge は ActiveXObject がサポートされていない他、セキュリティ設定の問題か、ローカルで Ajax ができないみたい。

以上

未だに IE しか使わせてもらえないレガシープログラマにとって、JScript・FileSystemObject はまだまだ現役。……泣ける話や……。

それにしても、FileSystemObject で読み込むと文字化けしないのはなんで?