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!