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


333

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

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

回答:


611

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

var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;

1
入力フィールドを備えたオンラインツールがあると便利です
holms 2013年

61
このようにそれを行うときは、バックスラッシュをエスケープする必要があり、例えばvar re = new RegExp("\\w+");
JD・スミス

12
@holms regex101.comも優れた正規表現オンラインツールです
Fran Herrero

2
後続のスラッシュが必要ないことを確認するのにしばらく時間がかかりました
Gerfried

2
@JDSmith私はあなたの例ではそれを意味しませんでした。ハードコーディングされている場合は、二重引用符を正規表現の一部にする場合は二重引用符をエスケープする必要があることを意味しました。明らかに、<input>HTMLタグのように文字列が変数内にある場合、これは当てはまりません。 var re = new RegExp("\"\\w+\"");は、RegExpコンストラクターを使用してハードコードされた正規表現の例であり、二重引用符のエスケープ必要です。変数の文字列var re = new RegExp(str);strは、問題なく二重引用符またはバックスラッシュを含めることができるということです。
Luis Paulo

66
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]);

のような無効な入力/\/が認識されることを考慮する必要があります。
ガンボ

8
または、複雑なパーサーを作成する代わりに、RegExpコンストラクターを失敗させ、「正規表現で\を追跡」します。
匿名

21

ここにワンライナーがあります: 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/

フラグサポート付きのタグ付きテンプレートリテラルの使用:

function str2reg(flags = 'u') {
    return (...args) => new RegExp(escapeStringRegExp(evalTemplate(...args))
        , flags)
}

function evalTemplate(strings, ...values) {
    let i = 0
    return strings.reduce((str, string) => `${str}${string}${
        i < values.length ? values[i++] : ''}`, '')
}

console.log(str2reg()`example.com`)
// => /example\.com/u


9

私の場合、ユーザー入力somethimesは区切り文字で囲まれており、場合によってはそうではありませんでした。したがって、別のケースを追加しました。

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);
}

3
.split()長い正規表現文字列の代わりに、常に関数を使用できます。 regParts = inputstring.split('/')これによりregParts[1]、正規表現文字列とregParts[2]区切り文字が作成されます(正規表現の設定がであると想定/.../gim)。で区切り文字があるかどうかを確認できregParts[2].length < 0ます。
Jaketr00

3

特別なフラグ用の個別のチェックボックスまたはテキストフィールドも追加することをお勧めします。これにより、ユーザーがを追加する必要がないことは明らかです//。置換の場合は、2つのテキストフィールドを提供します。これはあなたの人生をずっと簡単にします。

どうして?それ以外の場合は一部のユーザーがを追加し//、他のユーザーは追加しないためです。また、一部は構文エラーになります。次に、//' を取り除いた後、構文的に有効な正規表現がユーザーの意図とはまったく異なり、奇妙な動作(ユーザーの観点から)につながる可能性があります。


2

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

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

あなたがいる場合、実際に正規表現に文字列を変換するには、次の関数を使用してみてください:

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)
}

1

以前の回答のおかげで、このブロックは、構成可能な文字列を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

チェックボックスを使用してフラグを要求し、次のようなことを行うことができます:

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

以下のように見える正規表現は末尾の失われたpを ...スタックは私が1つの文字の編集を行うことはできないだろう
ジーンボー

-3

私はevalこの問題を解決するために使用します。

例えば:

    function regex_exec() {

        // Important! Like @Samuel Faure mentioned, Eval on user input is a crazy security risk, so before use this method, please take care of the security risk. 
        var regex = $("#regex").val();

        // eval()
        var patt = eval(userInput);

        $("#result").val(patt.exec($("#textContent").val()));
    }

3
userInputのevalはクレイジーなセキュリティリスクです
Samuel Faure

1
ミスターボビーテーブル!
Luiz Felipe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.