Crea RegExps al volo usando le variabili stringa


138

Supponiamo di voler rendere riutilizzabile quanto segue:

function replace_foo(target, replacement) {
   return target.replace("string_to_replace",replacement);
}

Potrei fare qualcosa del genere:

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(string_to_replace,replacement);
}

Con i letterali stringa questo è abbastanza facile. E se volessi diventare un po 'più complicato con la regex? Ad esempio, supponiamo che io voglia sostituire tutto ma string_to_replace . Istintivamente, proverei a estendere quanto sopra facendo qualcosa del tipo:

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(/^string_to_replace/,replacement);
}

Questo non sembra funzionare. La mia ipotesi è che pensi string_to_replacesia una stringa letterale, piuttosto che una variabile che rappresenta una stringa. È possibile creare regex JavaScript al volo usando le variabili stringa? Qualcosa del genere sarebbe fantastico se possibile:

function replace_foo(target, string_to_replace, replacement) {
   var regex = "/^" + string_to_replace + "/";
   return target.replace(regex,replacement);
}

Risposte:


215

C'è new RegExp(string, flags)dove flagssono go i. Così

'GODzilla'.replace( new RegExp('god', 'i'), '' )

valuta

zilla

31
E ometti i /delimitatori regex quando usi anche questo modulo.
cdhowie,

111

Con i letterali stringa questo è abbastanza facile.

Non proprio! L'esempio sostituisce solo la prima occorrenza di string_to_replace. Più comunemente si desidera sostituire tutte le occorrenze, nel qual caso è necessario convertire la stringa in un /.../gRegExp globale ( ). Puoi farlo da una stringa usando il new RegExpcostruttore:

new RegExp(string_to_replace, 'g')

Il problema è che qualsiasi carattere speciale di regex nella stringa letterale si comporterà in modi speciali invece di essere caratteri normali. Dovresti eseguire il backslash-escape per risolverlo. Sfortunatamente, non esiste una funzione integrata per farlo, quindi eccone una che puoi usare:

function escapeRegExp(s) {
    return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
}

Si noti inoltre che quando si utilizza un RegExp in replace(), la stringa di sostituzione ha ora un carattere speciale anche $. Questo deve essere evitato anche se vuoi avere un valore letterale $nel testo di sostituzione!

function escapeSubstitute(s) {
    return s.replace(/\$/g, '$$$$');
}

(Quattro $s perché questa è di per sé una stringa di sostituzione - argh!)

Ora puoi implementare la sostituzione globale di stringhe con RegExp:

function replace_foo(target, string_to_replace, replacement) {
    var relit= escapeRegExp(string_to_replace);
    var sub= escapeSubstitute(replacement);
    var re= new RegExp(relit, 'g');
    return target.replace(re, sub);
}

Che dolore. Fortunatamente se tutto ciò che vuoi fare è sostituire una stringa dritta senza parti aggiuntive di regex, c'è un modo più veloce:

s.split(string_to_replace).join(replacement)

...e questo è tutto. Questo è un linguaggio comunemente inteso.

dire che voglio sostituire tutto tranne string_to_replace

Cosa significa che vuoi sostituire tutti i tratti di testo che non prendono parte a una corrispondenza con la stringa? Una sostituzione ^sicuramente non lo fa, perché ^significa un token di inizio stringa, non una negazione. ^è solo una negazione nei []gruppi di caratteri. Ci sono anche punti di vista negativi (?!...), ma ci sono problemi con quello in JScript, quindi dovresti generalmente evitarlo.

Potresti provare ad abbinare "tutto fino a" la stringa e usare una funzione per scartare qualsiasi tratto vuoto tra stringhe corrispondenti:

var re= new RegExp('(.*)($|'+escapeRegExp(string_to_find)+')')
return target.replace(re, function(match) {
    return match[1]===''? match[2] : replacement+match[2];
});

Anche in questo caso, una divisione potrebbe essere più semplice:

var parts= target.split(string_to_match);
for (var i= parts.length; i-->0;)
    if (parts[i]!=='')
        parts[i]= replacement;
return parts.join(string_to_match);

10

Come hanno detto gli altri, usa new RegExp(pattern, flags)per fare questo. Vale la pena notare che passerai letterali di stringa in questo costruttore, quindi ogni barra rovesciata dovrà essere sfuggita. Se, ad esempio, volessi che il tuo regex corrisponda a una barra rovesciata, dovresti dirlo new RegExp('\\\\'), mentre il regex letterale dovrebbe essere solo /\\/. A seconda di come intendi utilizzarlo, dovresti essere cauto nel trasmettere l'input dell'utente a tale funzione senza un'adeguata elaborazione preliminare (escape di caratteri speciali, ecc.) Senza questo, i tuoi utenti potrebbero ottenere risultati molto inaspettati.


3
Questa risposta, sebbene non la più dettagliata, menziona un dettaglio cruciale su cui sono rimasto bloccato per un'ora: sfuggire a qualsiasi sequenza speciale. Ad esempio, stavo cercando una parola che inizia con un certo termine, quindi la regex di cui ho bisogno è /\b[term]\B/, ma quando la costruisco devo chiamare new RegExp("\\b"+ term + "\\B"). Piccola ma importante differenza e difficile da individuare poiché l'utilizzo come regex funziona direttamente come previsto.
Byson,


0

Penso di avere un ottimo esempio per evidenziare il testo in stringa (trova non guardare registro ma evidenziato usando register)

function getHighlightedText(basicString, filterString) {

    if ((basicString === "") || (basicString === null) || (filterString === "") || (filterString === null)) return basicString;

    return basicString.replace(new RegExp(filterString.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\\\$&'), 'gi'),
        function(match)
            {return "<mark>"+match+"</mark>"});

}

http://jsfiddle.net/cdbzL/1258/


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.