Artigo original: JavaScript Regex Match Example – How to Use JS Replace on a String

Expressões regulares, abreviadas como regex, ou, de vez em quando regexp, são um daqueles conceitos que você provavelmente sabe que são poderosos e muito úteis. Elas podem, porém, ser assustadoras, especialmente para programadores iniciantes.

Não precisa ser dessa forma. O JavaScript inclui vários métodos úteis que tornam o uso de expressões regulares muito mais gerenciável. Entre os métodos incluídos, temos os métodos .match(), .matchAll() e .replace(), que provavelmente são os que você usará com mais frequência.

Neste tutorial, veremos como funcionam esses métodos e analisaremos algumas razões para utilizá-los no lugar de outros métodos incluídos no JS.

Uma rápida introdução sobre expressões regulares

De acordo com a MDN, as expressões regulares são "padrões usados para corresponder a combinações de caracteres em strings".

Esses padrões, algumas vezes, podem incluir caracteres especiais (*, +), asserções (\W, ^), grupos e intervalos ((abc), [123]), além de outras coisas que tornam as regex tão poderosas e, ao mesmo tempo, difíceis de entender.

Em seu centro, as regex têm a ver com encontrar padrões em strings – tudo, de testar uma string para encontrar um caractere até a verificação de que um número de telefone é válido, pode ser feito com expressões regulares.

Se você acaba de conhecer as regex e gostaria de praticar um pouco antes de seguir lendo, confira nossos desafios de programação interativos.

Como usar o método .match()

Então, se as regex têm a ver com encontrar padrões em strings, você deve estar se perguntando o que torna o método .match() tão útil?

Diferente do método .test(), que apenas retorna true ou false, .match(), de fato, retornará a correspondência com uma string que você está testando. Aqui vemos um exemplo:

const citacaoDeCSLewis = 'Nós somos o que nós acreditamos que somos.';
const regex1 = /somos/;
const regex2 = /comemos/;

citacaoDeCSLewis.match(regex1); // ["somos", index: 4, input: "Nós somos o que nós acreditamos que somos.", groups: undefined]

citacaoDeCSLewis.match(regex2); // null

Isso pode ser bastante útil para alguns projetos, especialmente se você quiser extrair e manipular os dados que está correspondendo sem alterar a string original.

Se tudo o que você quer saber é se um padrão de busca é encontrado ou não, use o método .test() – é muito mais rápido.

São dois valores de retorno principais que você pode esperar do método .match():

  1. Se houver uma correspondência, o método .match() retornará um array com a correspondência. Entraremos em mais detalhes sobre isso em um instante.
  2. Se não houver uma correspondência, o método .match() retornará null.

Alguns de vocês já devem ter notado isso, mas se olharmos para o exemplo acima, .match() pega apenas a primeira ocorrência da palavra "somos".

Diversas vezes, queremos saber a frequência de correspondência de um padrão  com relação à string que está sendo testada. Vamos ver como fazer isso usando .match().

Modos diferentes de correspondência

Se houver uma correspondência, o array que .match() retornará terá dois modos diferentes, por assim dizer.

O primeiro modo é aquele quando a flag global (g) não é usada, como no exemplo acima:

const citacaoDeCSLewis = 'Nós somos o que nós acreditamos que somos.';
const regex = /somos/;

citacaoDeCSLewis.match(regex); // ["somos", index: 4, input: "Nós somos o que nós acreditamos que somos.", groups: undefined]

Neste caso, temos o array de .match() com a primeira correspondência, juntamente com o index (índice inicial) da correspondência na string original, a própria string original e os grupos de correspondência que foram usados.

Digamos, porém, que você queira ver quantas vezes a palavra "somos" ocorre em uma string. Para fazer isso, adicione a flag de busca global à sua expressão regular:

const citacaoDeCSLewis = 'Nós somos o que nós acreditamos que somos.';
const regex = /somos/g;

csLewisQuote.match(regex); // ["somos", "somos"]

Você não terá essas informações incluídas no modo "não global", mas terá um array com todas as correspondências na string que está testando.

Diferenciação entre maiúsculas e minúsculas

Algo importante para se lembrar é o fato de que as regex distinguem maiúsculas de minúsculas. Por exemplo, digamos que você queira ver quantas vezes a palavra "nós" ocorre na string:

const citacaoDeCSLewis = 'Nós somos o que nós acreditamos que somos.';
const regex = /nós/g;

citacaoDeCSLewis.match(regex); // ["nós"]

Neste caso, a correspondência é com um "n" minúsculo, seguido de "ós", também em minúsculas, que somente ocorre uma vez.

Se quiser todas as instâncias da palavra "nós", sejam iniciando em maiúsculas ou minúsculas, temos algumas opções.

Primeiro, você pode usar o método .toLowercase() na string antes de testá-la com o método .match():

const citacaoDeCSLewis = 'Nós somos o que nós acreditamos que somos.'.toLowerCase();
const regex = /nós/g;

citacaoDeCSLewis.match(regex); // ["nós", "nós"]

Caso queira preservar a distinção original, é possível adicionar a flag para evitar a distinção entre maiúsculas e minúsculas (i) à sua expressão regular:

const citacaoDeCSLewis = 'Nós somos o que nós acreditamos que somos.';
const regex = /nós/gi;

citacaoDeCSLewis.match(regex); // ["Nós", "nós"]

O novo método .matchAll()

Agora que você sabe sobre o método .match(), vale a pena falar do novo método .matchAll(), apresentado há pouco tempo.

Diferentemente do método .match(), que retorna um array ou null, .matchAll() exige a flag de busca global (g) e retorna um iterador ou um array vazio:

const citacaoDeCSLewis = 'Nós somos o que nós acreditamos que somos.';;
const regex1 = /nós/gi;
const regex2 = /comemos/gi;

[...citacaoDeCSLewis.matchAll(regex1)]; 
// [
//   ["Nós", index: 0, input: "Nós somos o que nós acreditamos que somos.", groups: undefined],
//   ["nós", index: 16, input: "Nós somos o que nós acreditamos que somos.", groups: undefined]
// ]

[...citacaoDeCSLewis.matchAll(regex2)]; // []

Embora pareça apenas um método .match() mais complicado, a principal vantagem que .matchAll() oferece é funcionar melhor com grupos de captura.

Aqui temos um pequeno exemplo:

const csLewisRepeat = "Nós Nós somos somos";
const repeatRegex = /(\w+)\s\1/g;

csLewisRepeat.match(repeatRegex); // ["Nós Nós", "somos somos"]
.match()
const csLewisRepeat = "Nós Nós somos somos";
const repeatRegex = /(\w+)\s\1/g;

[...repeatStr.matchAll(repeatRegex)];

// [
//   ["Nós Nós", "Nós", index: 0, input: "Nós Nós somos somos", groups: undefined],
//   ["somos somos", "somos", index: 8, input: "Nós Nós somos somos", groups: undefined],
// ]
.matchAll()

Mesmo que isso seja apenas o início, lembre-se de que provavelmente, é melhor usar .matchAll() se estiver usando a flag g e se quiser todas as informações adicionais que .match() fornece para uma única correspondência (índice inicial, a string original e assim por diante).

Como usar o método .replace()

Bem, agora que você sabe como usar os padrões de correspondência nas strings, provavelmente vá querer fazer algo de útil com essas correspondências.

Uma das coisas mais comuns que você fará ao encontrar um padrão de correspondência é substituir (em inglês, replace) aquele padrão por outra coisa. Por exemplo, talvez você queira substituir "paid" (pago) em "paidCodeCamp" por "free" (gratuito). A regex é uma boa maneira de se fazer isso.

Como .match() e .matchAll() retornam informações sobre os índices para cada padrão de correspondência, dependendo de como você os utiliza, pode usá-los para manipular strings de maneira elegante. Há, no entanto, um modo mais fácil – usar o método .replace().

Com .replace(), tudo o que você precisa é passar ao método uma string ou expressão regular que você queira corresponder como primeiro argumento e a string que a substituirá como segundo argumento:

const campString = 'paidCodeCamp';
const fCCString1 = campString.replace('paid', 'free');
const fCCString2 = campString.replace(/paid/, 'free');

console.log(campString); // "paidCodeCamp"
console.log(fCCString1); // "freeCodeCamp"
console.log(fCCString2); // "freeCodeCamp"

A melhor parte é que .replace() retorna uma nova string, sendo que a original permanece a mesma.

Semelhante ao método .match(), .replace() substituirá apenas o primeiro padrão correspondido, a menos que você use a regex com a flag g:

const campString = 'O paidCodeCamp é incrível. Confira o paidCodeCamp.';
const fCCString1 = campString.replace('paid', 'free');
const fCCString2 = campString.replace(/paid/g, 'free');

console.log(fCCString1); // "O freeCodeCamp é incrível. Confira o paidCodeCamp."
console.log(fCCString2); // "O freeCodeCamp é incrível. Confira o freeCodeCamp."

Da mesma forma que antes, é possível passar uma string ou uma expressão regular como o primeiro argumento. É importante lembrar de que o padrão correspondente distingue maiúsculas de minúsculas:

const campString = 'O PaidCodeCamp é incrível. Confira o PaidCodeCamp.';
const fCCString1 = campString.replace('Paid', 'free');
const fCCString2 = campString.replace(/paid/gi, 'free');

console.log(fCCString1); // "O freeCodeCamp é incrível. Confira o PaidCodeCamp."
console.log(fCCString2); // "O freeCodeCamp é incrível. Confira o freeCodeCamp."

Como usar o método .replaceAll()

Assim como .match() tem um método mais novo, .matchAll(), .replace() também tem o método .replaceAll().

A única diferença de fato entre .replace() e .replaceAll() é que você precisa usar a flag de busca global se usar uma expressão regular com .replaceAll():

const campString = 'O paidCodeCamp é incrível. Confira o paidCodeCamp.';
const fCCString1 = campString.replaceAll('paid', 'free');
const fCCString2 = campString.replaceAll(/paid/g, 'free');

console.log(fCCString1); // "O freeCodeCamp é incrível. Confira o freeCodeCamp."
console.log(fCCString2); // "O freeCodeCamp é incrível. Confira o freeCodeCamp."

O benefício real de .replaceAll() está no fato de ser mais legível e substituir todos os padrões com a correspondência ao passar a ele uma string como o primeiro argumento.

É isso! Agora você conhece o básico da substituição de strings com regex e alguns métodos de JS integrados. Esses foram exemplos bastante simples, mas espero que eu tenha conseguido mostrar a capacidade que até mesmo o uso de um pouco de regex pode ter.

Este artigo foi útil? Como você usaria os métodos .match(), .matchAll(), .replace() e .replaceAll()? Conte tudo para o autor pelo Twitter.