人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

JavascriptのRegExpオブジェクトをStringから生成したいです。
普通は
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を生成することができますか?


●質問者: test_31331
●カテゴリ:コンピュータ ウェブ制作
✍キーワード:ABC JavaScript js regexp String
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

1 ● GEN111
●27ポイント

こういうのはどうでしょう。

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"の"abc"と"i"を分離させずに正規表現となっているかを正規表現で調べる、という方法ですね。ありがとうございます。

ただ、やっぱりevalで泥臭さが見えるのかも、というのは私の偏見ですかね(笑)

"/abc/i"という表現が、すでに正規表現を表す「記号」としての役割を果たしているので、new RegExp("/abc/i") みたいなもので生成できるように実装されててもいいんじゃないかと思えます。/abc/iがRegExpオブジェクトと振る舞う中で、引数としてRegExpオブジェクトをとるように見えるnew RegExp(/abc/i)はちょっと異質にも見えます。


2 ● ofk
●13ポイント
function getRegExp(exp) {
try {
return (new Function('', 'return ' + exp))();
}
catch(e) {
return new RegExp;
}
}
var a = getRegExp("/abc/i");
alert(a.source);

こんなのはどうでしょうか?

◎質問者からの返答

任意のコードを実行されないようにしたいので、

js> a = getRegExp("alert('abc')")

のようなコードを実行すると、任意のコードが実行できるかたちになってしまいます。

これはちょっと質問に沿わなくなってしまいます。

また、よい方法を思いついたらご回答ください。

ありがとうございます。


3 ● Mug
●40ポイント ベストアンサー

> 任意のコードを実行されないようにしたいので、

半分は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のためで、毎回実行される関数外に書きたいけれど、外から参照・変更されたくないため、使用しました。

◎質問者からの返答

一番ベターな方法のようです。

これでやってみようかと思います。ありがとうございました。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ