web-dev-qa-db-ja.com

ユーザー入力文字列を正規表現に変換する

私はHTMLとJavaScriptで正規表現テスターを設計しています。ユーザは正規表現、文字列を入力し、ラジオボタンを介してテストしたい機能(例えば検索、一致、置換など)を選択し、その機能が指定された引数で実行されるとプログラムは結果を表示する。当然のことながら、追加の引数を置き換えるための追加のテキストボックスなどがあります。

私の問題は、ユーザーから文字列を取得してそれを正規表現に変換することです。私が彼らが入力する正規表現の周りに//を持つ必要がないと言うならば、彼らはgiのようにフラグを設定することができません。それで、彼らは式の周りに//を持っている必要があります、しかしどのように私はその文字列を正規表現に変換することができますか?文字列なのでリテラルにはできません。また、//がないと、文字列ではないのでRegExpコンストラクタに渡すことはできません。ユーザー入力文字列を正規表現にする他の方法はありますか?正規表現の文字列とフラグを//で解析しなければなりませんか?それからそれを別の方法で構築しますか?文字列を入力してからフラグを別々に入力する必要がありますか。

303

文字列から正規表現を作成するには、 RegExpオブジェクトコンストラクタ を使用します。

var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;
561
Gumbo
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);

または

var match = inputstring.match(new RegExp('^/(.*?)/([gimy]*)$'));
// sanity check here
var regex = new RegExp(match[1], match[2]);
62
Anonymous

これがワンライナーです:str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

escape-string-regexp NPMモジュールから入手しました。

試してみる:

escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
function escapeStringRegExp(str) {
    return str.replace(escapeStringRegExp.matchOperatorsRe, '\\$&');
}

console.log(new RegExp(escapeStringRegExp('example.com')));
// => /example\.com/
13
Rivenfall

JavaScript RegExpオブジェクトコンストラクタ を使用してください。

var re = new RegExp("\\w+");
re.test("hello");

コンストラクタへの2番目の文字列引数としてflagsを渡すことができます。詳細はドキュメントを参照してください。

13
Ayman Hourieh

私の場合、ユーザー入力は区切り文字で囲まれている場合と囲まれていない場合があります。したがって、別のケースを追加しました。

var regParts = inputstring.match(/^\/(.*?)\/([gim]*)$/);
if (regParts) {
    // the parsed pattern had delimiters and modifiers. handle them. 
    var regexp = new RegExp(regParts[1], regParts[2]);
} else {
    // we got pattern string without delimiters
    var regexp = new RegExp(inputstring);
}
9
staabm

これは、文字列が無効であるか、フラグなどが含まれていない場合にも機能します。

function regExpFromString(q) {
  let flags = q.replace(/.*\/([gimuy]*)$/, '$1');
  if (flags === q) flags = '';
  let pattern = (flags ? q.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1') : q);
  try { return new RegExp(pattern, flags); } catch (e) { return null; }
}

console.log(regExpFromString('\\bword\\b'));
console.log(regExpFromString('\/\\bword\\b\/gi'));
            
2
kofifus

特別なフラグ用に別のチェックボックスまたはテキストフィールドを追加することをお勧めします。そうすれば、ユーザーが//を追加する必要がないことは明らかです。置き換えの場合は、two textfieldsを指定してください。これはあなたの人生をずっと楽にするでしょう。

どうして?そうでなければ何人かのユーザは//を追加するでしょうが他の人はそうしません。そして、いくつかは構文エラーを作ります。それから、//を取り除いた後は、構文的に有効な正規表現になってしまい、ユーザーの意図したものとは違うものになり、(ユーザーの視点から見て)奇妙な振る舞いにつながります。

2
Stephan202

以前の回答のおかげで、このブロックはテキストをフィルタリングするためにRegExに設定可能な文字列を適用するための汎用的な解決策として役立ちます。

var permittedChars = '^a-z0-9 _,.?!@+<>';
permittedChars = '[' + permittedChars + ']';

var flags = 'gi';
var strFilterRegEx = new RegExp(permittedChars, flags);

log.debug ('strFilterRegEx: ' + strFilterRegEx);

strVal = strVal.replace(strFilterRegEx, '');
// this replaces hard code solt:
// strVal = strVal.replace(/[^a-z0-9 _,.?!@+]/ig, '');
1
Gene Bo

もしあなたが本当に文字列を正規表現に変換したいのなら、次の関数を使ってみてください。

function String2Regex(s){return new RegExp(s.match(/\/(.+)\/.*/)[1], s.match(/\/.+\/(.*)/)[1]);}

あなたはそのようにそれを使うことができます:

"abc".match(String2Regex("/a/g"))
> ["a"]

参考のために、ここにフォーマットされた、より近代的なバージョンを示します。

const String2Regex = str => {
  // Main regex
  const main = str.match(/\/(.+)\/.*/)[1]

  // Regex options
  const options = str.match(/\/.+\/(.*)/)[1]

  // Return compiled regex
  return new RegExp(main, options)
}
0
Richie Bendall

チェックボックスを使用してフラグを要求してから、次のようにします。

var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);
0
Pim Jager