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?

Gordon Gustafson
quelle

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;
Gumbo
quelle
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]);
Anonym
quelle
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
Rivenfall
quelle
15

Verwenden Sie den JavaScript RegExp-Objektkonstruktor .

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

Sie können Flags als zweites Zeichenfolgenargument an den Konstruktor übergeben. Einzelheiten finden Sie in der Dokumentation.

Ayman Hourieh
quelle
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);
}
staabm
quelle
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).

Stephan202
quelle
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'));
            

Kofifus
quelle
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)
}
Richie Bendall
quelle
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, '');
Gene Bo
quelle
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);
Pim Jäger
quelle
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()));
    }
Playhi
quelle
3
eval on userInput ist ein verrücktes Sicherheitsrisiko
Samuel Faure
1
Herr Bobby Tische!
Luiz Felipe