Stringクラスに対する拡張(1)
【抜粋】一部省略 Object.extend(String.prototype, { stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); }, (省略) inspect: function() { return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; } });
既存Stringクラスにメソッドを追加しています。
stripTagsメソッド
【抜粋】 stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); },
文字列(this)から、タグ部分を削除しています。
正しく取り除けない場合
この正規表現だと正しくタグを取り除けない場合があります。
【例】 alert("<input type='text' value='>'/>TEST".stripTags()); //「TEST」でなく、「'/>TEST」と表示されてしまう。
これに対応させるためには以下のようにします。
【修正案1】(これでもダメな場合があります。後述。) stripTags: function() { return this.replace(/<\/?[^"'>]*(?:(?:"[^"]*"|'[^']*')[^"'>]*)*\/?>/gi, ''); },
「ループ展開」という技法により記述されています。参考にしたのは以下です。
正規表現辞典 (DESKTOP REFERENCE) 05-02-05 HTML/XMLの開始タグにマッチさせたい
この出展はさらに「詳説 正規表現 第2版」にあるようです。
厳密にタグを取り除く
上記だと以下の場合に正しく取り除けません。
【例】 alert('<input type="text" value="\\">"/>TEST'.stripTags()); //「TEST」でなく、「"/>TEST」と表示されてしまう。
このケースにも対応させてみました。
【修正案】 stripTags: function() { return str.replace(/<\/?[^"'>]*(?:(?:"(?:\\"|[^"])*"|'(?:\\'|[^'])*')[^"'>]*)*\/?>/gi, ''); },
たぶんこれでいけると思うのですが。まぁ、素直にエスケープさせとけ、という話ではあります^^;
stripScripts
【抜粋】 stripScripts: function() { return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); },
文字列(this)から、scriptブロックを削除するメソッドです。前述PrototypeオブジェクトのScriptFragmentプロパティからscriptブロックの正規表現文字列を取得しています。
replaceメソッド第二引数のm修飾子は、正規表現をマルチラインモードにするためのものですが、Prototype.ScriptFragmentには「^」「$」が使われていないので意味がない気がします。
【参考】正規表現 マルチラインモード var str = "1_line\n2_line"; alert(str); //1_line //2_line と表示(\nは改行) var matches = str.match(/^2_line/); alert(matches); //'null'と表示される。マッチしてない。 matches = str.match(/^2_line/m); //マルチラインモード alert(matches); //'2_line'と表示される。「^」が行頭にマッチした。
extractScriptsメソッド
extractScripts: function() { var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); },
文字列(this)のすべてのscriptブロックの内容を、配列に格納して返却するメソッドです。
Prototype.ScriptFragmentを使用して、グローバルマッチする正規表現オブジェクトと、シングルマッチする正規表現オブジェクトを作成しています。m修飾子は無意味な気がします。
少しややこしいですが、文字列(this)からすべてのscriptブロックを抽出し、更にそれぞれからscriptブロックの内容(コード部分)を抽出して配列に格納し、返却しています。
mapメソッドはArrayクラスに追加されているメソッドです*1。引数に指定された関数を、配列要素すべてを順番に引数に指定して実行し、結果を配列に格納して返却します。
以下の一行はscriptブロックの内容を抜き出して返却しています。マッチしなければ空文字(['', '']の2番目の'')を返却しますが、このケースは発生しない気がします。
【抜粋】 return (scriptTag.match(matchOne) || ['', ''])[1];
シングルモードのマッチングの場合でも、返却されるのは配列です。インデックス0にマッチした全体の文字列、インデックス1以降に、「(pattern)」でグルーピングした部分にマッチした文字列が順次格納されます。ただし、「(」の直後に「?:」があると後方参照不可となり、格納されません。
【参考】正規表現 シングルモードのマッチング var str = "aaabbbcccdddeee"; var matches = str.match(/a+(b+)(?:c+)(d+)/); alert(matches[0]); //"aaabbbcccddd"と表示される alert(matches[1]); //"bbb"と表示される alert(matches[2]); //"ddd"と表示される //参考 RegExpオブジェクトによる取得 alert(RegExp.$1); //"bbb"と表示される alert(RegExp.$2); //"ddd"と表示される
正規表現についての参考文献
正規表現の説明はあまり詳しくはしません(というかできません^^;)。他サイトや文献を参考にしてください。現在筆者が参考にしているのは以下です。(他書との比較検討はしていませんが、とりあえずやりたいことを調べる時には重宝しています)
正規表現辞典 (DESKTOP REFERENCE)