Como você usa uma variável em uma expressão regular?

1380

Gostaria de criar um String.replaceAll()método em JavaScript e estou pensando que usar um regex seria a maneira mais concisa de fazê-lo. No entanto, não consigo descobrir como passar uma variável para uma regex. Eu posso fazer isso já que irá substituir todas as instâncias de "B"com "A".

"ABABAB".replace(/B/g, "A");

Mas eu quero fazer algo assim:

String.prototype.replaceAll = function(replaceThis, withThis) {
    this.replace(/replaceThis/g, withThis);
};

Mas, obviamente, isso substituirá apenas o texto "replaceThis"... então, como passo essa variável para minha string regex?

JC Grubbs
fonte
9
No momento, estamos trabalhando para adicionar essa funcionalidade ao JavaScript, se você tiver uma opinião sobre isso, por favor, participe da discussão.
Benjamin Gruenbaum

Respostas:

1842

Em vez de usar a /regex/gsintaxe, você pode construir um novo objeto RegExp :

var replace = "regex";
var re = new RegExp(replace,"g");

Você pode criar dinamicamente objetos regex dessa maneira. Então você fará:

"mystring".replace(re, "newstring");
Eric Wendelin
fonte
272
Se você precisar usar uma expressão como /\/word\:\w*$/ , certifique-se de escapar de seus barras invertidas: new RegExp( '\\/word\\:\\w*$' ).
Jonathan Swinney
2
@gravityboy Você pode fazer ('' + meuNúmero). substituir (/ 10 / g, 'a') ou, se quiser números hexadecimais, pode fazer parseInt ('' + meuNúmero, 16) para converter para hexadecimal de decimal.
Eric Wendelin
29
A pergunta sugere que o RegEx é usado apenas para fazer uma substituição de seqüência constante. Portanto, esta resposta está errada, pois falharia se a sequência contivesse meta caracteres RegEx. Triste que seja votado tão alto, fará muitas dores de cabeça ...
dronus
16
Um exemplo dessa passagem de uma variável tornaria essa uma boa resposta. Eu ainda estou lutando depois de ler isso.
Ganso
3
@ JonathanSwinney: /não tem significado especial se você construir regex a partir de uma string, para que você não precise escapar dela. /\/word\:\w*$/deveria sernew RegExp('/word\\:\\w*$')
Dávid Horváth
211

Como Eric Wendelin mencionou, você pode fazer algo assim:

str1 = "pattern"
var re = new RegExp(str1, "g");
"pattern matching .".replace(re, "regex");

Isso gera "regex matching ." . No entanto, ele falhará se str1 for ".". Você esperaria que o resultado fosse "pattern matching regex", substituindo o período por "regex", mas acabará sendo ...

regexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregex

Isso ocorre porque, embora "."seja uma String, no construtor RegExp ainda é interpretado como uma expressão regular, significando qualquer caractere que não seja de quebra de linha, ou seja, todos os caracteres da string. Para esse fim, a seguinte função pode ser útil:

 RegExp.quote = function(str) {
     return str.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
 };

Então você pode fazer:

str1 = "."
var re = new RegExp(RegExp.quote(str1), "g");
"pattern matching .".replace(re, "regex");

cedendo "pattern matching regex".

Gracenotes
fonte
4
Você sabe que o primeiro parâmetro a substituir pode ser uma sequência normal e não precisa ser uma regexp? str1 = "."; alert ("correspondência de padrões.". replace (str1, "string"));
algum dia
@ alguns: é claro. Isso ocorre porque o exemplo acima é trivial. Quando você precisar procurar ou substituir um padrão combinado com uma sequência regular, execute str.match (new RegExp ("https?: //" + RegExp.escape (myDomainName))), por exemplo. É irritante que a função de escape seja não construído em.
Gracenotes
(continuação) Além disso, o aparente JC Grubbs exigiu uma substituição global; implementar uma substituição global por String.replace (String, String) pode ser lento para entradas grandes. Só estou dizendo que as duas principais soluções são incorretas e falharão inesperadamente em determinadas entradas.
Gracenotes
4
developer.mozilla.org/pt-BR/docs/JavaScript/Guide/… oferece uma função semelhante, mas eles excluem -e incluem =!:/.
chbrown
8
O termo correto é "escape", não "quote". Apenas entre.
Lawrence Dol
118

"ABABAB".replace(/B/g, "A");

Como sempre: não use regex a menos que você precise. Para uma substituição simples de cadeia, o idioma é:

'ABABAB'.split('B').join('A')

Então você não precisa se preocupar com os problemas de citação mencionados na resposta do Gracenotes.

bobince
fonte
11
E você mediu que isso é mais rápido que o regex?
quer
3
Isso parece preferível, especialmente quando é necessário combinar caracteres regex especiais como '.'
Krease
1
Uhm ... Também não é necessário dividir um RegExp; Nesse caso, não causaria o mesmo problema? De qualquer forma ... .split (). Join () pode ser mais lento em algumas plataformas, porque são duas operações, enquanto .replace () é uma operação e pode ser otimizado.
5
@ PacMan--: ambos splite replacepodem pegar uma string ou um RegExpobjeto. O problema que replacetem isso splitnão é que, quando você usa uma string, obtém apenas uma única substituição.
bobince
1
referência aqui: jsperf.com/replace-vs-split-join-vs-replaceall/23
Wagner da Silva
38

Se você deseja obter TODAS as ocorrências ( g), faça distinção entre maiúsculas e minúsculas ( i) e use limites para que não seja uma palavra dentro de outra palavra ( \\b):

re = new RegExp(`\\b${replaceThis}\\b`, 'gi');

Exemplo:

let inputString = "I'm John, or johnny, but I prefer john.";
let replaceThis = "John";
let re = new RegExp(`\\b${replaceThis}\\b`, 'gi');
console.log(inputString.replace(re, "Jack")); // I'm Jack, or johnny, but I prefer Jack.
JBallin
fonte
obrigado! (Afinal, a sua é a única resposta explicitamente com a rxinterpolação Emacs / style, por meio de strings de modelo.)
sam boosalis
34

Para quem procura usar variável com o método match , isso funcionou para mim

var alpha = 'fig';
'food fight'.match(alpha + 'ht')[0]; // fight
Steven Penny
fonte
31

Este:

var txt=new RegExp(pattern,attributes);

é equivalente a isso:

var txt=/pattern/attributes;

Consulte http://www.w3schools.com/jsref/jsref_obj_regexp.asp .

Jeremy Ruten
fonte
20
sim, mas em primeiro exemplo que ele usa patterncomo variável, no 2º como uma string
vladkras
20
this.replace( new RegExp( replaceThis, 'g' ), withThis );
tvanfosson
fonte
Gosto dessa resposta, pois ela não cria a variável extra (e sem sentido).
Wick
14

Você deseja construir a expressão regular dinamicamente e, para isso, a solução adequada é usar o new RegExp(string)construtor. Para que o construtor trate caracteres especiais literalmente , você deve escapar deles. Há uma função interna no widget de preenchimento automático da UI do jQuery chamada $.ui.autocomplete.escapeRegex:

[...] você pode fazer uso da $.ui.autocomplete.escapeRegexfunção embutida. Será necessário um único argumento de string e escapará a todos os caracteres regex, tornando o resultado seguro para passar new RegExp().

Se você estiver usando a interface do usuário do jQuery, poderá usar essa função ou copiar sua definição da fonte :

function escapeRegex( value ) {
    return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
}

E use-o assim:

"[z-a][z-a][z-a]".replace(new RegExp(escapeRegex("[z-a]"), "g"), "[a-z]");
//            escapeRegex("[z-a]")       -> "\[z\-a\]"
// new RegExp(escapeRegex("[z-a]"), "g") -> /\[z\-a\]/g
// end result                            -> "[a-z][a-z][a-z]"
Salman A
fonte
9
String.prototype.replaceAll = function (replaceThis, withThis) {
   var re = new RegExp(replaceThis,"g"); 
   return this.replace(re, withThis);
};
var aa = "abab54..aba".replaceAll("\\.", "v");

Teste com esta ferramenta

unigogo
fonte
5
String.prototype.replaceAll = function(a, b) {
    return this.replace(new RegExp(a.replace(/([.?*+^$[\]\\(){}|-])/ig, "\\$1"), 'ig'), b)
}

Teste como:

var whatever = 'Some [b]random[/b] text in a [b]sentence.[/b]'

console.log(whatever.replaceAll("[", "<").replaceAll("]", ">"))
MetalGodwin
fonte
4

Aqui está outra implementação replaceAll:

    String.prototype.replaceAll = function (stringToFind, stringToReplace) {
        if ( stringToFind == stringToReplace) return this;
        var temp = this;
        var index = temp.indexOf(stringToFind);
        while (index != -1) {
            temp = temp.replace(stringToFind, stringToReplace);
            index = temp.indexOf(stringToFind);
        }
        return temp;
    };
scripto
fonte
4

E a versão coffeescript da resposta de Steven Penny, já que este é o resultado # 2 do google .... mesmo que o café seja apenas javascript com muitos caracteres removidos ...;)

baz = "foo"
filter = new RegExp(baz + "d")
"food fight".match(filter)[0] // food

e no meu caso particular

robot.name=hubot
filter = new RegExp(robot.name)
if msg.match.input.match(filter)
  console.log "True!"
afiado
fonte
por que um voto negativo? coffeescript -IS- javascript com sua própria sintaxe específica.
afiado
robot.name=hubotnão é javascript.
codepleb 31/01
3

Embora você possa criar RegExp criados dinamicamente (conforme as outras respostas a esta pergunta), repetirei meu comentário em um post semelhante : A forma funcional de String.replace () é extremamente útil e, em muitos casos, reduz a necessidade de objetos RegExp criados dinamicamente. (que é meio doloroso porque você precisa expressar a entrada para o construtor RegExp como uma sequência de caracteres, em vez de usar o formato literal de barras / [AZ] + / regexp)

Jason S
fonte
3

Para satisfazer minha necessidade de inserir uma variável / alias / function em uma Expressão Regular, é isso que eu criei:

oldre = /xx\(""\)/;
function newre(e){
    return RegExp(e.toString().replace(/\//g,"").replace(/xx/g, yy), "g")
};

String.prototype.replaceAll = this.replace(newre(oldre), "withThis");

onde 'oldre' é o regexp original que eu quero inserir uma variável, 'xx' é o espaço reservado para essa variável / alias / function e 'yy' é o nome, o alias ou a função real da variável.

Alex Li
fonte
2

Você pode usar isso se $ 1 não funcionar com você

var pattern = new RegExp("amman","i");
"abc Amman efg".replace(pattern,"<b>"+"abc Amman efg".match(pattern)[0]+"</b>");
Alnamrouti com tarifa
fonte
1

Você sempre pode usar indexOfrepetidamente:

String.prototype.replaceAll = function(substring, replacement) {
    var result = '';
    var lastIndex = 0;

    while(true) {
        var index = this.indexOf(substring, lastIndex);
        if(index === -1) break;
        result += this.substring(lastIndex, index) + replacement;
        lastIndex = index + substring.length;
    }

    return result + this.substring(lastIndex);
};

Isso não entra em um loop infinito quando a substituição contém a correspondência.

Ry-
fonte
1

Sua solução está aqui:

Passe uma variável para expressão regular.

O que eu implementei é pegar o valor de um campo de texto que você deseja substituir e outro é o campo de texto "substituir por", obtendo o valor do campo de texto em uma variável e definindo a variável como RegExp função para substituir ainda mais. No meu caso, estou usando o Jquery, você também pode fazê-lo apenas com JavaScript.

Código JavaScript:

  var replace =document.getElementById("replace}"); // getting a value from a text field with I want to replace
  var replace_with = document.getElementById("with"); //Getting the value from another text fields with which I want to replace another string.

  var sRegExInput = new RegExp(replace, "g");    
  $("body").children().each(function() {
    $(this).html($(this).html().replace(sRegExInput,replace_with));
  });

Este código está no evento Onclick de um botão, você pode colocar isso em uma função para chamar.

Então agora você pode passar variáveis ​​na função de substituição.

Ajit Hogade
fonte
Sua variável substituir_por conterá o elemento DOM não o valor em si
Ben Taliadoros
1

Essa função de auto-chamada itera sobre o substiterItems usando um índice e altera o substituerItems [index] globalmente na cadeia a cada passagem.

  const replacerItems = ["a", "b", "c"];    

    function replacer(str, index){
          const item = replacerItems[index];
          const regex = new RegExp(`[${item}]`, "g");
          const newStr = str.replace(regex, "z");
          if (index < replacerItems.length - 1) {
            return replacer(newStr, index + 1);
          }
          return newStr;
    }

// console.log(replacer('abcdefg', 0)) will output 'zzzdefg'

fonte
0

Nenhuma dessas respostas estava clara para mim. Acabei encontrando uma boa explicação em http://burnignorance.com/php-programming-tips/how-to-use-a-variable-in-replace-function-of-javascript/

A resposta simples é:

var search_term = new RegExp(search_term, "g");    
text = text.replace(search_term, replace_term);

Por exemplo:

$("button").click(function() {
  Find_and_replace("Lorem", "Chocolate");
  Find_and_replace("ipsum", "ice-cream");
});

function Find_and_replace(search_term, replace_term) {
  text = $("textbox").html();
  var search_term = new RegExp(search_term, "g");
  text = text.replace(search_term, replace_term);
  $("textbox").html(text);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textbox>
  Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum
</textbox>
<button>Click me</button>

Paul Chris Jones
fonte
1
Você está substituindo uma variável de fechamento, não precisa usar varaqui. Além disso, se você passar \bou \1ele iria quebrar.
CyberAP
0

Para substituição múltipla sem expressões regulares, fui com o seguinte:

      let str = "I am a cat man. I like cats";
      let find = "cat";
      let replace = "dog";


      // Count how many occurrences there are of the string to find 
      // inside the str to be examined.
      let findCount = str.split(find).length - 1;

      let loopCount = 0;

      while (loopCount < findCount) 
      {
        str = str.replace(find, replace);
        loopCount = loopCount + 1;
      }  

      console.log(str);
      // I am a dog man. I like dogs

A parte importante da solução foi encontrada aqui

John Shearing
fonte