普通は
js> a = new RegExp("abc", "i")
js> a.source # => "abc"
とすればよいのですが、
"/abc/i"のような文字列から先のようなRegExpを作ろうと思うと
js> a = new RegExp("/abc/i")
js> a.source # => "\/abc\/i"
のようになってしまいます。そこでevalを使うと
js> a = eval("/abc/i")
js> a.source # => "abc"
のようにほしいRegExpが作れることまでわかっています。
しかし、"/abc/i"のような文字列が安全かどうかわからない場合に、evalを使いたくありません。つまり
js> a = eval("while(true){alert('abc')}")
のようなことができないようにしたいです。
RegExpで、"/abc/i"の"abc"と"i"を分離させて、そこからRegExpを新たに生成するという方法もありますが、
ちょっと泥臭いので、もう少しスマートに、"/abc/i"のような文字列から、任意のコードを実行されないように、適切なRegExpを生成することができますか?
> 任意のコードを実行されないようにしたいので、
半分はGEN111さんのと同じですが、以下のような感じでは如何でしょうか?
var Pattern = (function() {
var PatternOfPattern = /^\/(.+)\/([gim]*)$/i;
return function(pattern) {
if((typeof pattern) != "string") {
throw new Error("引数patternは文字列でなければなりません。");
} else if(!PatternOfPattern.test(pattern)) {
throw new Error("引数patternの値は正規表現リテラルの形式を満たしていません。");
}
PatternOfPattern.exec(pattern);
return new RegExp(RegExp.$1, RegExp.$2);
};
})();
//-------------------------------
var regObj1 = Pattern ("/^hoge\\s+.*;$/i");
var regObj2 = new RegExp("^hoge\\s+.*;$", "i");
alert(regObj1 == regObj2); // -> false
alert(regObj1.source == regObj2.source); // -> true
引数patternの文字列自体を取り出せるように拡張することも可能です。
また、new RegExpの部分はわざとtry~catchしていません。これは正規表現としての文法エラーはこのPattern関数内部で隠蔽しないほうが逆によいのでは?と考えたためです。
クロージャを使ったのは、2箇所(test,exec)で使用する変数PatternOfPatternのためで、毎回実行される関数外に書きたいけれど、外から参照・変更されたくないため、使用しました。
こういうのはどうでしょう。
var res1 = "/abc/i" ; var res2 = 'alert("")' ; var reo1 = eval(String(res1.match(/^\/.*\/[gim]*$/))) ; alert(reo1 == undefined) ; var reo2 = eval(String(res2.match(/^\/.*\/[gim]*$/))) ; alert(reo2 == undefined) ; // 文字列が正規表現にならない場合は undefined
"/abc/i"という表現が、すでに正規表現を表す「記号」としての役割を果たしているので、new RegExp("/abc/i") みたいなもので生成できるように実装されててもいいんじゃないかと思えます。
<<
そうしてしまうと、/\/abc\/i/で書き表せる正規表現をnew RegExpで生成する方法がなくなってしまいます。
そうしてしまうと、/\/abc\/i/で書き表せる正規表現をnew RegExpで生成する方法がなくなってしまいます。
<<
new RegExp("/\/abc\/i/")
という感じでどうでしょうか?
>>
引数としてRegExpオブジェクトをとるように見えるnew RegExp(/abc/i)はちょっと異質にも見えます。
<<
object の代入が参照渡しになってしまうので、それができないとコピー作るのが面倒ですからね。
>>
一番ベター
<<
それってベスト?
求めていた回答では、デフォルトの関数ひとつで、具体的にいえば、new RegExp("/abc/i")のような感じで
できるというのがベストでした。
ただ、今回はそういった方法はやっぱり存在しないようなので、1番はボツ。だから一番ベターだった2番手が
いるか賞というわけです。
>>
object の代入が参照渡しになってしまうので、それができないとコピー作るのが面倒ですからね。
<<
駆け出しなもので、いまいち掴めてないですが、
a = new RegExp("abc")
b = a
b == a // => true
b = new RegExp(a)
b == a // => false
あたりのことと想像します。まだそこら辺を意識したことがなかったので、
そういうこともあったと片隅においておくことにします。ありがとうございます。