Conversione della stringa di input dell'utente in espressione regolare


333

Sto progettando un tester di espressioni regolari in HTML e JavaScript. L'utente inserirà una regex, una stringa e sceglierà la funzione con cui desidera testare (ad esempio ricerca, corrispondenza, sostituzione, ecc.) Tramite il pulsante di opzione e il programma visualizzerà i risultati quando tale funzione viene eseguita con gli argomenti specificati. Naturalmente ci saranno caselle di testo extra per gli argomenti extra da sostituire e simili.

Il mio problema è ottenere la stringa dall'utente e trasformarla in un'espressione regolare. Se dico che non hanno bisogno di avere //intorno alla regex in cui entrano, allora non possono impostare bandiere, come ge i. Quindi devono avere il carattere //intorno all'espressione, ma come posso convertire quella stringa in regex? Non può essere un valore letterale poiché è una stringa e non posso passarlo al costruttore RegExp poiché non è una stringa senza di essa //. Esiste un altro modo per trasformare una stringa di input dell'utente in una regex? Dovrò analizzare la stringa e le bandiere del regex con il //'s quindi costruirlo in un altro modo? Devo farli inserire una stringa e quindi inserire le bandiere separatamente?

Risposte:


611

Utilizzare il costruttore di oggetti RegExp per creare un'espressione regolare da una stringa:

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

1
sarebbe bello avere uno strumento online con un campo di input
holms

61
Quando lo fai in questo modo, devi sfuggire alla barra rovesciata, ad esempiovar re = new RegExp("\\w+");
JD Smith,

12
@holms regex101.com è anche un ottimo strumento online di regex
Fran Herrero,

2
Mi ci è voluto un po 'di tempo per capire che non sono necessarie barre posteriori
Gerfried il

2
@JDSmith Non intendevo nel tuo esempio. Volevo dire che è necessario sfuggire alle doppie virgolette se si desidera che facciano parte del regex a condizione che sia codificato. Ovviamente, nulla di tutto ciò si applica se la stringa si trova in una variabile come da un <input>tag HTML. var re = new RegExp("\"\\w+\"");è un esempio di regex hard coded che utilizza il costruttore RegExp ed è necessario scappare tra virgolette doppie . Quello che intendo con una stringa in una variabile è che puoi semplicemente fare var re = new RegExp(str);e strpuò contenere virgolette doppie o barre rovesciate senza problemi.
Luis Paulo,

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

o

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

È necessario considerare che /\/viene riconosciuto un input non valido come .
Gumbo,

8
O lasciare che il costruttore RegExp fallisca, "trascinando \ in espressione regolare", invece di scrivere un parser complicato.
Anonimo

21

Ecco un one-liner: str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

L'ho preso dal modulo NPM escape-string-regexp .

Provandolo:

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

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

Utilizzo dei valori letterali modello con tag con supporto flag:

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

Nel mio caso, l'input dell'utente a volte era circondato da delimitatori e talvolta no. quindi ho aggiunto un altro caso ..

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
puoi sempre usare la .split()funzione invece di una lunga stringa regex. regParts = inputstring.split('/')questo renderebbe regParts[1]la stringa regex e regParts[2]i delimitatori (supponendo che l'installazione di regex sia /.../gim). È possibile verificare se sono presenti delimitatori con regParts[2].length < 0.
Jaketr00,

3

Ti suggerisco di aggiungere anche caselle di controllo separate o un campo di testo per le bandiere speciali. In questo modo è chiaro che l'utente non ha bisogno di aggiungere alcun //. In caso di sostituzione, fornire due campi di testo. Questo renderà la tua vita molto più semplice.

Perché? Perché altrimenti alcuni utenti aggiungeranno quelli //mentre altri no. E alcuni commetteranno un errore di sintassi. Quindi, dopo aver rimosso gli elementi //, potresti avere una regex sintatticamente valida che non assomiglia a ciò che l'utente intendeva, portando a comportamenti strani (dal punto di vista dell'utente).


2

Questo funzionerà anche quando la stringa non è valida o non contiene flag, ecc:

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

Se vuoi davvero convertire una stringa in regex, prova a usare la seguente funzione:

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

Puoi usarlo così:

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

Per riferimento, ecco la versione formattata e più moderna:

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

Grazie alle risposte precedenti, questo blocco serve anche come soluzione di uso generale per l'applicazione di una stringa configurabile in un RegEx .. per filtrare il testo:

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

Puoi chiedere le bandiere usando le caselle di controllo, quindi fai qualcosa del genere:

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

appare come RegEx manca trailing p .. Pila non mi permetteva di fare una modifica 1 carattere
Gene Bo

-3

Uso evalper risolvere questo problema.

Per esempio:

    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 è un folle rischio per la sicurezza
Samuel Faure,

1
Signor Bobby Tavoli!
Luiz Felipe
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.