日々のコンピュータ情報の集積と整理

Dr.ウーパのコンピュータ備忘録

2015年2月18日水曜日

Bloggerだとページ中のJavaScriptの一部の文字が自動的にエスケープされてしまう。その時に取った対応

イントロダクション

コンマ(,)区切りの文字列の要素を、括弧[]でそれぞれ囲むサービスを作りました」で公開したプログラムを、実際に Blogger のページに張り付けて運用してみたところ、一部でうまく動作していないことが分かりました。

どうも、全角のダブルクォーテーション(“”)が入力データに入っていると、ちゃんと変換してくれないようです。

Blogger のページに張り付ける前に、パソコンのローカルの html ファイルでテストした時には同じ条件で正常に動作していました。



何故かと思い、Blogger のページのソースコードを見ていたら原因が分かりました。
そのときの、Blogger のページのソースコードを以下に貼り付けます。

なお、元のソースコードは、以下のページにあります。

プログラムソース:コンマ(,)区切りの文字列の要素を、括弧[]でそれぞれ囲む - ver1.0
http://upa-pc.blogspot.com/2015/02/Src-Comma-Separated-Words-to-Square-Bracket-Separated-v1.0.html


Blogger のサーバから出力された、ページのソースコード

<form onsubmit="return false;">
<strong>(ダブルクォーテーション(")で囲まれた)コンマ(,)区切りの文字列 :</strong><br />
<input id="input-text" style="width: 700px;" type="text" /><br />
<input checked="checked" id="auto-focus-move" type="checkbox" />自動的に結果を選択する<br />
例&#65289;&#8220;Dr.ウーパ , コンピュータ備忘録 , Blog&#8221;
</form>
<form onsubmit="return false;">
<strong>括弧[]でそれぞれの要素を囲んだ結果&#65306;</strong><br />
<input id="output-text" onfocus="this.select();" style="width: 700px;" type="text" />
</form>
<br />
<script type="text/javascript">
//<![CDATA[
<!--
(function () {

var id_input = "input-text"; // 入力値を保持する要素の id
var id_output = "output-text"; // 出力値を保持する要素の id

// 前回検査時の入力値
var input_old_text = "";

// 定期的に入力を監視し&#12289;入力が変化していたら&#12289;出力する
setInterval((function () {

// 入力されたダブルクォーテーション(")で囲まれたコンマ(,)区切りの文字列
var input_text = document.getElementById(id_input).value;

if (input_text != input_old_text) {

// 入力されたダブルクォーテーション(")で囲まれたコンマ(,)区切りの文字列を&#12289;
// 括弧[](角括弧&#12289;大括弧&#12289;ブラケット)でそれぞれ囲んだ文字列に変換する
var output_text = changeInputText(input_text);

document.getElementById(id_output).value = output_text;
if (document.getElementById("auto-focus-move").checked) {
document.getElementById(id_output).select();
}

input_old_text = input_text;

}

}), 500);

/*
入力されたダブルクォーテーション(")で囲まれたコンマ(,)区切りの文字列を&#12289;
括弧[](角括弧&#12289;大括弧&#12289;ブラケット)でそれぞれ囲んだ結果を返す
*/
function changeInputText(input_text) {

return "[" +
input_text.replace(/["&#8220;&#8221;]/g, "")
.replace(/\s*[,&#65292;]\s*/g, "][") +
"]";
}


var debug_flag = false;
if (debug_flag) {

/* テスト用 */
(function () {

var error_count = 0;

(function () {
var input = "&#8220;Dr.ウーパ&#65292;コンピュータ備忘録 , Blog&#8221;";
var output = changeInputText(input);
var error = output != "[Dr.ウーパ][コンピュータ備忘録][Blog]";
if (error) error_count++;
console.log("input," + input + ",output," + output + ",error," + error);
})();
(function () {
var input = "\"Dr.ウーパ , コンピュータ備忘録&#65292;Blog\"";
var output = changeInputText(input);
var error = output != "[Dr.ウーパ][コンピュータ備忘録][Blog]";
if (error) error_count++;
console.log("input," + input + ",output," + output + ",error," + error);
})();
(function () {
var input = "Dr ウーパ コンピュータ 備忘録 &#65292; Bl og";
var output = changeInputText(input);
var error = output != "[Dr ウーパ コンピュータ 備忘録][Bl og]";
if (error) error_count++;
console.log("input," + input + ",output," + output + ",error," + error);
})();

console.log("error_count," + error_count);
if (error_count > 0) {
console.log("Test NG");
} else {
console.log("Test OK");
}
})();
}
})();

//-->
//]]>
</script>


お分かりいただけたでしょうか?

なんと、Blogger のページ中に記載した JavaScript コードの、一部の全角文字がエスケープ処理されています。


Blogger のページ中に記載した JavaScript コードの、一部の全角文字がエスケープ処理されている

例えば、次の正規表現による置換の部分を見てみましょう。

return "[" +
input_text.replace(/["&#8220;&#8221;]/g, "")
.replace(/\s*[,&#65292;]\s*/g, "][") +
"]";

もともとのソースコードでは、以下のようになっていました。

            return "[" +
                input_text.replace(/["“”]/g, "")
                    .replace(/\s*[,,]\s*/g, "][") +
                "]";


以下のような変換が行われていることが分かります。

“” の部分が、&#8220;&#8221;
, の部分が、&#65292;


全角のダブルクォーテーションや、全角のコンマがエスケープ処理されています。


これでは、JavaScript コードが期待通りに動くはずがありません。

このようなエスケープされた表現が html ファイルのソースコード中にあった場合には、html として表現されている部分では、アンエスケープ(&#8220; が “ として見える・取得できる)されたデータを見たり・得たりすることができます。

しかし、JavaScript コード中にそのような表現があった場合には、html 中の文字とは解釈が異なるため、アンエスケープされません


なお、このデータの変換は、Blogger のサーバからページが配信されるときに行われていると考えられます。


なぜなら、ページを編集するときに表示した HTML や、保存したページを再編集した時の HTML では、このようなエスケープ処理された表現になっていなかったからです。

従って、Blogger の内部的にはエスケープ処理される前のデータを持っていますが、実際にBlogger のサーバから閲覧者へデータが配信されるまでの間でこのようなエスケープ処理が行われていることになります。


このような変換を止めるような設定なども見当たらなかったため、このような変換が行われる前提で、正常に動作するようにコードを書き換える必要があります。


どう対処するべきか?

JavaScript 中の文字列リテラルが自動的にエスケープされてしまうのであれば、それらの文字列リテラルを利用する前に、エスケープされた文字をアンエスケープする処理を挟んでやればいいことになります。


この文字のアンエスケープをやるには、いくつかの方法があります。

例えば、element オブジェクトを生成し、その innerHTML にアンエスケープされた文字列データを設定すれば、そのテキストデータ(textContent || innerText) を取得すれば、アンエスケープされたデータが取得できるでしょう。

または、html 中に JavaScript で利用する(エスケープされてしまう)文字列を記載しておき、それを JavaScript で取得すれば、アンエスケープされた文字列を取得できます。


今回は、後者の方法で実装することにしました。

次のように、input タグの隠しデータとして、JavaScript で利用するデータを埋め込んでおきます。

    <input type="hidden" id="reg-exp-double-quotes-list" value="&quot;“”" />
    <input type="hidden" id="reg-exp-comma-list" value=",," />


そして、そのデータを JavaScript 中で要素から取得します。

            // ダブルクォーテーション(") 認識用データ
            var double_quotes_array = document.getElementById("reg-exp-double-quotes-list").value.split("");
            var double_quotes_str = double_quotes_array.join("");

            // コンマ(,)認識用データ
            var comma_array = document.getElementById("reg-exp-comma-list").value.split("");
            var comma_str = comma_array.join("");


そして、そのデータを実際に使いたかった部分で使用します。

                return "[" +
                    input_text.replace(new RegExp("[" + double_quotes_str + "]", "g"), "")
                        .replace(new RegExp("\\s*[" + comma_str + "]\\s*", "g"), "][") +
                    "]";


なお、正規表現の部分では、元々使用していた /pattern/flags という形式では、正規表現のパターン部分に変数の値を使うことができなかったため、new RegExp("pattern" [, "flags"]) の形式に書き直しました。



それらの修正を行った、コンマ(,)区切りの文字列の要素を、括弧[]でそれぞれ囲むサービスのソースコードを以下のページに記載しました。







関連記事

関連記事を読み込み中...

同じラベルの記事を読み込み中...