Replace() de string multiplo em Javascript

Compartilhe nas redes sociais

Olá pessoal, tudo bem?

Vou falar um pouco sobre algo muito útil porém pouco conhecido a respeito do String.prototype.replace do Javascript.

O básisco

Simples assim:

const sayMyName = "Olá me chamo José";

console.log(sayMyName.replace("José", "Maria"));

O código acima substitui a palavra José (primeiro parâmetro) por Maria (segundo parâmetro).

O primeiro parâmetro do método replace do objeto String pode ser uma string ou uma expressão regular (regex). Se você não sabe trabalhar com regex indico aqui um material muito bom e muito didático! Seria bom até mesmo você procurar saber o minímo de regex antes de prosseguir com a leitura. =D

O segundo parâmetro pode ser uma string ou uma função, e se escolhermos a segunda opção tudo começa a ficar mais divertido.

Nós podemos ler a expressão regular /%([a-zA-Z]+)/ como: “case tudo que for letras maiúsculas e minúsculas e que inicie com um sinal de porcentagem”. Então se tivermos uma string que seja “Olá, eu sou o %nome”, o %nome irá “casar” com nossa regex. Com isso nós podemos fazer o que quisermos com esse valor casado se o capturarmos usando o método replace.

Não entendeu? Vamos passo a passo.

Por exemplo o seguinte código:

const regex = /%([a-zA-Z]+)/gm;
const phrase = "Olá, me chame de %nome";
const str = phrase.replace(regex, "José");
  
// na variável str, %nome foi substituído por "José"

No código acima usamos uma string no segundo parâmetro, mas, poderíamos ter usado uma função. Segue o exemplo abaixo.

const regex = /%([a-zA-Z]+)/gm;
const phrase = "Olá, me chame de %nome";
const str = phrase.replace(regex, nameReplacement);
  
function nameReplacement() {
  return "José";
}
// na variável str, %nome foi novamente substituído por "José"

Sacou? O retorno da função é o que é usado para fazer a substituição no método replace. No nosso caso retornamos a string “José”, mas poderia ser “Developer”. Abra o console aí e faça testes você mesmo.

Bom, agora que você entendeu me responda, o que aconteceria se a string em que queremos fazer substituições tivesse duas vezes %nome? Ou uma vez %nome e uma vez ou mais %algumacoisa? Bora testar:

const regex = /%([a-zA-Z]+)/gm;
const phrase = "Olá, me chame de %nome ou %idade %profissao";
const str = phrase.replace(regex, nameReplacement);
  
function nameReplacement() {
  return "José";
}
// na variável str %nome, %idade e %profissao foram todos substituídos por "José"

Exatamente, nossa regex casa com qualquer palavra que venha precedido por um sinal de porcentagem e pra cada ocorrência ele executa a função do segundo parâmetro e sempre usa seu retorno para fazer o replace. Mas isso só acontece por causa do G (global) ali no fim da regex /%([a-zA-Z]+)/gm. Sem ele o replace para na primeira ocorrência encontrada e ignora o resto.

Se tiver dúvidas sobre regex estude! Vale a pena!

Legal! Mas o que dá pra fazer de útil com isso?

A partir daqui podemos fazer o replace múltiplo das informações. Porém antes vamos ver mais uma coisa a respeito do segundo parâmetro.

Essa função que passamos pro método replace, recebe também alguns parâmetros conforme o exemplo abaixo:

function nameReplacement(match, p1, p2, p3) {

  return "José";
}

match: é a string exata que foi casada, no nosso caso “%nome”, “%idade” ou “%profissao” cada uma em sua iteração.

p1, p2, p3, p4… são os valores casados porém apenas o que está entre os parênteses da regex. Na nossa regex %([a-zA-Z]+) o que estará entre parênteses será tudo que vem precedido pelo sinal de porcentagem (excluindo o próprio sinal %), ou seja, %(profissao), %(idade), %(nome). Sendo assim, os valores respectivos de p1, p2, p3 serão “nome”, “idade”, “profissao”…

A quantidade de argumentos p1, p2, p-n que sua função receberá vai depender da quantidade de “()”  incluídos na sua regex.

Na nossa função só teremos p1, pois, nossa regex só tem 1 grupo (parênteses) inserido, %([a-zA-Z]+). Se nossa regex fosse (%)([a-zA-Z]+) daí então teríamos p1 e p2 como parâmetro também.

Vamos ver como ficaria no código:

const regex = /(%)([a-zA-Z]+)/gm;
const phrase = "Olá, me chame de %nome";
const str = phrase.replace(regex, nameReplacement);
  
function nameReplacement(match, p1, p2) {
  // match = "%nome";
  // p1 = "%";
  // p2 = "nome";

  return "José";
}

Existem ainda outros parâmetros que a função recebe, offset e string:

function nameReplacement(match, p1, p2, offset, string) {
  // match = "%nome";
  // p1 = "%";
  // p2 = "nome";

  // offset. O offset da string encontrada em relação ao resto da string. Por exemplo, se a string for 'abcd' e a string a ser encontrada for 'bc', então este parâmetro terá o valor 1.

  // string. A string completa que está sendo examinada.

  return "José";
}

Estes últimos 2 parâmetros não são úteis para nós agora, mas, você pode usar sua criatividade e adaptar de acordo com sua necessidade.

Vamos finalizar agora com um exemplo realmente útil?

Bora!

const phrase = "Olá! Eu sou um(a) %animal e sei %sound";

const animals = [
  {
    animal: 'gato',
    sound: 'miar'
  },
  {
    animal: 'cachorro',
    sound: 'latir'
  },
  {
    animal: 'galinha',
    sound: 'cacarejar'
  }
];

let index = 0;

const regex =/%([a-zA-Z]+)/gm;

const arr_animals = animals.map((animal, idx) => {
  index = idx;
  return phrase.replace(regex, replaceAll)
});

console.log(arr_animals)

// console.log:
// ["Olá! Eu sou um(a) gato e sei miar", "Olá! Eu sou um(a) cachorro e sei latir", "Olá! Eu sou um(a) galinha e sei cacarejar"]

function replaceAll(matched, p1) {
  return animals[index][p1]
}

Acima nós usamos o map para iterar o array animals. A cada iteração nós recebemos no map um dos objetos que representa cada animal e a sua posição (idx) no array.

Dentro do map a primeira coisa que fazemos é atualizar a variável global index com o valor de idx. Logo em seguida nós chamamos o método replace na variável phrase passando como argumentos um regex e a função replaceAll.

No método replaceAll nós acessamos a posição x do array animals através da variável index, e usando o valor do parâmetro p1 que nesse caso pode ser “name” ou “sound” nós acessamos a respectiva proriedade no objeto que está sendo iterado em animals. Então, retornamos seu valor na função e esse valor é inserido na substituição de %name ou %sound na variável phrase.

Bem legal né? Um pouco complexo também, até poderia ser o início de um algoritmo bem básico de template engine. hehe!

Enfim, espero ter ajudado com essa dica sobre o String.prototype.replace.

Dúvidas, críticas ou sugestões são sempre bem vindas.

Até a próxima pessoal!