Konvertieren der Benutzereingabezeichenfolge in einen regulären Ausdruck


331

Ich entwerfe einen Tester für reguläre Ausdrücke in HTML und JavaScript. Der Benutzer gibt einen regulären Ausdruck und eine Zeichenfolge ein und wählt die Funktion, mit der er testen möchte (z. B. Suchen, Übereinstimmen, Ersetzen usw.), über das Optionsfeld aus. Das Programm zeigt die Ergebnisse an, wenn diese Funktion mit den angegebenen Argumenten ausgeführt wird. Natürlich gibt es zusätzliche Textfelder für die zu ersetzenden zusätzlichen Argumente und dergleichen.

Mein Problem besteht darin, die Zeichenfolge vom Benutzer abzurufen und in einen regulären Ausdruck umzuwandeln. Wenn ich sage, dass sie keine //Regex-Zeichen haben müssen , die sie eingeben, können sie keine Flags wie gund setzen i. Sie müssen also das //'s um den Ausdruck haben, aber wie kann ich diesen String in einen regulären Ausdruck konvertieren? Es kann kein Literal sein, da es eine Zeichenfolge ist, und ich kann es nicht an den RegExp-Konstruktor übergeben, da es keine Zeichenfolge ohne die //Zeichen ist. Gibt es eine andere Möglichkeit, eine Benutzereingabezeichenfolge in einen regulären Ausdruck zu verwandeln? Muss ich den String und die Flags der Regex mit den //'s analysieren und dann anders konstruieren? Soll ich sie eine Zeichenfolge eingeben lassen und dann die Flags separat eingeben?

Antworten:


609

Verwenden Sie den RegExp-Objektkonstruktor , um einen regulären Ausdruck aus einer Zeichenfolge zu erstellen:

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

1
Es wäre schön, ein Online-Tool mit einem Eingabefeld zu haben
Holms

60
Wenn Sie dies auf diese Weise tun, müssen Sie dem Backslash entkommen, z. B.var re = new RegExp("\\w+");
JD Smith

12
@holms regex101.com ist auch ein großartiges Regex-Online-Tool
Fran Herrero

2
Es hat eine Weile gedauert, bis ich festgestellt habe, dass keine nachgestellten Schrägstriche erforderlich sind
Gerfried

2
@JDSmith Ich habe es in deinem Beispiel nicht so gemeint. Ich meinte, dass Sie doppelte Anführungszeichen vermeiden müssen, wenn Sie möchten, dass sie Teil der Regex sind, vorausgesetzt, sie sind fest codiert. Dies gilt natürlich nicht, wenn sich die Zeichenfolge in einer Variablen wie einem <input>HTML-Tag befindet. var re = new RegExp("\"\\w+\"");ist ein Beispiel für einen fest codierten regulären Ausdruck, der den RegExp-Konstruktor verwendet, und das Escapezeichen der doppelten Anführungszeichen ist erforderlich. Was ich mit einer Zeichenfolge in einer Variablen meine, ist, dass Sie dies problemlos tun können var re = new RegExp(str);und strdoppelte Anführungszeichen oder Backslashes enthalten können.
Luis Paulo

66
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);

oder

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

Sie sollten berücksichtigen, dass eine ungültige Eingabe wie /\/erkannt wird.
Gumbo

8
Oder lassen Sie den RegExp-Konstruktor "Trailing \ in regulären Ausdrücken" fehlschlagen, anstatt einen komplizierten Parser zu schreiben.
Anonym

21

Hier ist ein Einzeiler: str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

Ich habe es vom Escape-String-Regexp- NPM-Modul erhalten.

Probieren Sie es aus:

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

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

Verwenden von markierten Vorlagenliteralen mit Unterstützung für Flags:

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

In meinem Fall war die Benutzereingabe manchmal von Trennzeichen umgeben und manchmal nicht. deshalb habe ich noch einen fall hinzugefügt ..

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
Sie können die .split()Funktion immer anstelle einer langen Regex-Zeichenfolge verwenden. regParts = inputstring.split('/')Dies würde regParts[1]die Regex-Zeichenfolge und regParts[2]die Trennzeichen bilden (vorausgesetzt, das Setup der Regex ist /.../gim). Sie können überprüfen, ob Trennzeichen mit vorhanden sind regParts[2].length < 0.
Jaketr00

3

Ich schlage vor, dass Sie auch separate Kontrollkästchen oder ein Textfeld für die speziellen Flags hinzufügen. Auf diese Weise ist klar, dass der Benutzer keine hinzufügen muss //. Geben Sie im Falle eines Ersetzens zwei Textfelder an. Dies wird Ihr Leben viel einfacher machen.

Warum? Weil sonst einige Benutzer //'s hinzufügen , während andere nicht. Und einige machen einen Syntaxfehler. Nachdem Sie die //s entfernt haben, erhalten Sie möglicherweise einen syntaktisch gültigen regulären Ausdruck, der nicht dem entspricht, was der Benutzer beabsichtigt hat, was zu seltsamem Verhalten führt (aus Sicht des Benutzers).


2

Dies funktioniert auch, wenn die Zeichenfolge ungültig ist oder keine Flags usw. Enthält:

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

Wenn Sie eine Zeichenfolge wirklich in einen regulären Ausdruck konvertieren möchten, verwenden Sie die folgende Funktion:

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

Sie können es so verwenden:

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

Als Referenz ist hier die formatierte und modernere Version:

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

Dank früherer Antworten eignet sich dieser Block als allgemeine Lösung zum Anwenden einer konfigurierbaren Zeichenfolge in eine RegEx .. zum Filtern von Text:

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

Sie können mithilfe von Kontrollkästchen nach Flags fragen und dann Folgendes tun:

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

Es sieht so aus, als ob RegEx das hintere p fehlt . Stack würde mich nicht 1 Zeichen bearbeiten lassen
Gene Bo

-3

Ich benutze eval, um dieses Problem zu lösen.

Zum Beispiel:

    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
eval on userInput ist ein verrücktes Sicherheitsrisiko
Samuel Faure

1
Herr Bobby Tische!
Luiz Felipe
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.