イントロダクション
「コンマ(,)区切りの文字列の要素を、括弧[]でそれぞれ囲むサービスを作りました」で公開したプログラムを、実際に 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 /> 例)“Dr.ウーパ , コンピュータ備忘録 , Blog” </form> <form onsubmit="return false;"> <strong>括弧[]でそれぞれの要素を囲んだ結果:</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 = ""; // 定期的に入力を監視し、入力が変化していたら、出力する setInterval((function () { // 入力されたダブルクォーテーション(")で囲まれたコンマ(,)区切りの文字列 var input_text = document.getElementById(id_input).value; if (input_text != input_old_text) { // 入力されたダブルクォーテーション(")で囲まれたコンマ(,)区切りの文字列を、 // 括弧[](角括弧、大括弧、ブラケット)でそれぞれ囲んだ文字列に変換する 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); /* 入力されたダブルクォーテーション(")で囲まれたコンマ(,)区切りの文字列を、 括弧[](角括弧、大括弧、ブラケット)でそれぞれ囲んだ結果を返す */ function changeInputText(input_text) { return "[" + input_text.replace(/["“”]/g, "") .replace(/\s*[,,]\s*/g, "][") + "]"; } var debug_flag = false; if (debug_flag) { /* テスト用 */ (function () { var error_count = 0; (function () { var input = "“Dr.ウーパ,コンピュータ備忘録 , 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.ウーパ , コンピュータ備忘録,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 ウーパ コンピュータ 備忘録 , 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(/["“”]/g, "")
.replace(/\s*[,,]\s*/g, "][") +
"]";
もともとのソースコードでは、以下のようになっていました。
return "[" +
input_text.replace(/["“”]/g, "")
.replace(/\s*[,,]\s*/g, "][") +
"]";
以下のような変換が行われていることが分かります。
“” の部分が、“”
, の部分が、,
全角のダブルクォーテーションや、全角のコンマがエスケープ処理されています。
これでは、JavaScript コードが期待通りに動くはずがありません。
このようなエスケープされた表現が html ファイルのソースコード中にあった場合には、html として表現されている部分では、アンエスケープ(“ が “ として見える・取得できる)されたデータを見たり・得たりすることができます。
しかし、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=""“”" />
<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"]) の形式に書き直しました。
RegExp - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp
それらの修正を行った、コンマ(,)区切りの文字列の要素を、括弧[]でそれぞれ囲むサービスのソースコードを以下のページに記載しました。
コメントを投稿
コメント投稿機能について