Regex: Um guia prático para expressões regulares

Aprenda regex de forma simples e fcil!

Photo by Fran . on Unsplash

Em toda nossa vida como programadores estaremos lidando com regex em algum momento. Seja para coisas comuns como validar emails ou data e at mesmo para fazer parse em textos em busca de um determinado padro.

Nesse post, irei mostrar de forma simples e fcil como voc pode criar suas prprias expresses regulares. Todos os exemplos sero feitos usando javascript, porm, muito das regex criadas aqui tambm funcionaro em outras linguagens como elixir, python, php ou ruby.

O que uma expresso regular?

De forma simples:

Uma expresso regular um mtodo formal de se especificar um padro de texto.

Com ela podemos lidar com as seguintes situaes:

  • procura;
  • substituio;
  • validao de formatos;
  • filtragem de informaes

Criando nossas primeiras regex

Usando javascript podemos optar por duas formas de se criar uma regex. Podemos criar usando um constructor:

const regex = new RegExp(‘dog’,’gi’);

Ou criando de forma literal:

const regex = /dog/gi

Podemos buscar por somente uma letra:

pattern: /a/string: A casa est limpa.matches: ^

Ou buscar por uma palavra:

pattern: /celular/string: O celular est tocando.matches: ^^^^^^^

Podemos ver que, na primeira regex, ela ignorou o primeiro A. Isso acontece porque as regex so case sensitive. Notamos tambm na primeira regex que s houve match na primeira ocorrncia. Para lidar com isso, usaremos flags.

Flags

Elas adicionam comportamentos adicionais a nossas regras, como:

  • g – indicar achar todas as ocorrncias da regex
  • i – ignora case sensitive
  • m – multilinha, lida com caracteres de inicio e fim (^ e $) ao operar em mltiplas linhas.

Podemos ento obter todas as ocorrncias com a flag g e em conjunto com a flag i podemos ignorar o case sensitive de uma busca:

pattern: /ontem/gistring: Ontem faltou gua, Anteontem faltou luzmatches:^^^^^ ^^^^^

Operador pipe ” | ?

Algumas vezes precisamos dar match em mais de um termo, para isso usamos o operador pipe | . Ele funciona basicamente como nosso operador lgico OR || . Assim podemos escrever:

pattern: /ver|distrai/gistring: Ver a linha do horizonte me distraimatches:^^^ ^^^^^^^pattern: /20|nove/gistring: Perdi 20 em 20 e nove amizadesmatches: ^^ ^^ ^^^^pattern: /e|m|/gistring: E = mcmatches: ^ ^ ^

Conjuntos ? [ ] ?

Com os conjuntos dizemos a regex que uma determinada casa pode ter diversos valores para dar match. Vejamos o seu uso:

pattern: /[em]/gistring: E = mcmatches: ^ ^ ^

Uma funcionalidade interessante de adicionar range (invervalos) dentro dos nossos conjuntos. Podemos determinar um conjunto de match em letras que vo de A Z ou pegue qualquer digito (0 9).

pattern: /[a-z]/string: Joo de Santo Cristomatches: ^ ^ ^^ ^^^^ ^^^^^pattern: /[A-Za-z]/string: Aucar e Cafmatches: ^ ^^^^ ^ ^^pattern: /[0-9.,]/string: Um ps4 custa R$ 1.600,00matches: ^ ^^^^^^^^

Um detalhe a ser observado que o range obedece a mesma ordem da tabela Unicode, sendo assim regex como [a-Z] ou [4-1] produziram erro, pois ambas no esto na ordem correta da tabela Unicode.

Podemos tambm dar match em letras com acentos (-) ou () usando:

pattern: /[-]/string: Aa melhormatches: ^^^^ ^ ^^^^^^

Temos tambm os conjuntos negados, que como o nome sugere, dar match em tudo que no faa parte do conjunto. Para defin-lo iniciamos a regra do conjunto com ^ , por exemplo [^a-z] que aceita tudo que no seja entre a z. Vejamos um exemplo:

pattern: /[^aeiou]/gistring: Paraleleppedomatches: ^ ^ ^ ^ ^ ^ ^

Metacaracteres

Nas regex existem duas formas de caracteres, os literais, que representam o valor literal do caractere como abc123 e os metacaracteres que possuem funes distintas dentro de um contexto na regex. Dois exemplos que acabamos de ver so o uso do ^ iniciando um conjunto negado e o uso do – em uma regra de conjunto com range[1-9] . Um metacaractere bastante recorrente o ponto . , ele funciona como um coringa, sendo capaz de dar match em qualquer caractere, vejamos um exemplo:

pattern: /cas./gistring: Casa, caso, casematches: ^^^^ ^^^^ ^^^^

Visto isso, voc deve estar se perguntando: Como pegar a forma literal do ponto? Eis que muito simples bastando usar um escape mais o metacaractere desejado. Vejamos um exemplo:

pattern: /[a-o]/gistring: cachorro-quente.matches: ^ ^ ^^

Para simplificar a escrita e leitura das regex, possumos algumas shorthands que so extremamente teis para deixar ainda mais claro nosso cdigo. Veja como podemos escrever esse conjunto [0-9] para d ,[a-zA-Z0-9_] para w ou para tratar espaos em branco [rntfv ] para s simplificando ainda mais nossas regras. Vejamos alguns exemplos:

pattern: /(dd)sddddd-dddd/string: (86) 95262-7297matches: ^^^^^^^^^^^^^^^pattern: /wwww[emailprotected]ww.com/string: [emailprotected]: ^^^^^^^^^^^^

Para um guia de consulta, criei um gist contendo muitos metacaracteres e shorthands e seus respectivos significado.

Quantificadores

Uma maneira de deixar suas regras ainda mais simples com o uso dos quantificadores. Com eles podemos dizer quantas vezes uma mesma regra pode aparecer em sequncia. Vejamos elas:

  • ? – zero ou um ocorrncia;
  • * – zero ou mais ocorrncias;
  • + – uma ou mais ocorrncias;
  • {n, m} – de n at m.

Seu uso simples, basta adicionar o quantificador aps um caractere, metacaractere, conjunto ou mesmo um grupo (ainda veremos abaixo). Exemplo [0-9]? w* a+ e (d){1,3} .

Digamos que queremos pegar um documento como o cpf, que contm muitos nmeros e pontuaes(. e -) onde a validao pode aceitar o cpf com e sem pontuao, ficando deste modo:

pattern: /d{3}.?d{3}.?d{3}-?d{2}/string: 825.531.760-07matches: ^^^^^^^^^^^^^^string: 18646661024matches: ^^^^^^^^^^^

Como podemos pegar uma repetio de caractere sem estipular algum limite, vejamos:

pattern: /go+l+/gistring: Goolllll da Alemanha!!!matches: ^^^^^^^^

ncoras

Muitas vezes vamos precisar delimitar a ao da nossa regex. Desse modo podemos usar trs metas para nos auxiliar nessa funo.

Quando queremos tratar uma palavra que em suas extremidades no possua outra letra ou palavra, usamos a shorthands b.

pattern: /bparb/gistring: Parcela par Parcial parasomatches: ^^^pattern: /bpar[a-z]+/gistring: Parei parque toparmatches: ^^^^^ ^^^^^^ pattern: /[a-z]+parb/gistring: parodiado escapar equipar parasitarmatches: ^^^^^^^ ^^^^^^^pattern: /b[a-z]+par[a-z]+b/gistring: limpar aparto apartamatches: ^^^^^^ ^^^^^^

Vale notar que caracteres com acentos ou – so considerados bordas.

Podemos lidar com o incio e fim de uma linha. Usamos a meta ^ para indicar o incio de uma linha e $ indicando o fim de uma linha. Algo importante a se notar que para as ncoras funcionarem a cada quebra de linha n a flag m tem que estar habilitada. Segue uma estrofe usando a meta ^:

pattern: /^[a-z]*b/gmiQuantas chances desperdicei^^^^^^^Quando o que eu mais queria^^^^^^Era provar pra todo o mundo^^^Que eu no precisava provar nada pra ningum^^^

Confira tambm o uso do meta $ em uma estrofe:

pattern: /[a-z]+nto$/gmiO tempo cobre o cho de verde manto ^^^^^Que j coberto foi de neve fria,E em mim converte em choro o doce canto ^^^^^

Conseguimos tratar incio e final de um texto ao mesmo tempo. Confira um exemplo:

pattern: /^https://w{3}.[a-z]+.com$/gmihttps://google.com.brhttps://www.facebook.com^^^^^^^^^^^^^^^^^^^^^^^^https://www.voxel.com.br

Grupos ? () ?

Por fim, temos os grupos que facilita ainda mais nossas regras. Eles nos possibilita a criao de regras isoladas, possibilita a criao de referencias (retrovisores) para o reuso da mesma regra em outro local dentro de uma mesmo regex e ainda cria a possibilidade de validaes dentro da regex. Seu uso muito diverso, dando muito poder ao programador na hora de escrever suas regras. Veja um exemplo:

pattern: /(d{2})/?(d{2})?/(d{4})/string: Hoje dia 20/01/2020matches: ^^^^^^^^^^

Uma funo muito interessante dos grupos que quando criamos algum grupo, este grupo criando uma referncia, que podemos acessa-lo em funes como o mtodo replace (que vamos ver a frente) ou usar como retrovisores (mirror words) para fazer reuso de algum grupo que deu match anteriormente. Vejamos um exemplo baseado no exemplo anterior:

pattern: /d{2}(/?)d{2}?1d{4}/gstring: 20/01/2020 25091991 25-09/2000matches: ^^^^^^^^^^ ^^^^^^^^

No exemplo acima, veja que criamos o grupo (/?) e para no repet-lo em outro momento que necessitamos da mesma regra, usamos o retrovisor 1 sendo 1 ligado a ordem em que esse grupo foi criado. Podemos criar diversas referncias para o reuso de regras.

Uma dica se por exemplo usamos um grupo (w) o seu retrovisor ser o caractere que deu match com w. Ex: w = R seu 1 sera R.

Podemos definir grupos que podem ser ignorados (non-capturing groups) na hora do match usando a sintaxe (?:). Vejamos um exemplo:

pattern: /([a-z]*)s(?:ronaldo)/gistring: Cristiano Ronaldomatches: ^^^^^^^^^^^^^^^^^

No exemplo acima, s foi nomeado um grupo, no caso ([a-z]*) pois o grupo (?:ronaldo) foi definido usando (?:) e com isso no conseguimos manipul-lo.

Com os grupos podemos criar grupos aninhados (grupos dentro de grupos). Vejamos um exemplo:

pattern: /((d[io])|(co))([a-z]{2})(do)/gistring: ditado colado dosadomatches: ^^^^^^ ^^^^^^ ^^^^^^

Os grupos possuem grupos especiais. Como o positive lookahead (?=) e o seu oposto, negative lookahead (?!). Com o positive lookahead podemos verificar se existe um grupo a frente de uma expresso ou grupo. Vejamos um exemplo:

pattern: /([a-z]+)(?=,)/gistring: Penso, logo existomatches: ^^^^^

Falamos acima que a regex s d match em palavras que sua frente possuam virgula. J o negative lookahead exatamente o contrrio do positive lookahed, ele pegar todos que no fazem parte do grupo especial. Vejamos um exemplo:

pattern: /([a-z]+)(?!,)b/gistring: Penso, logo existomatches: ^^^^ ^^^^^^

Dentro dos grupos especiais ainda temos os positive lookbehind e negative lookbehind, porm como eles no possuem um bom suporte nos browsers decidi deix-lo de fora deste post, porm pretendo abord-los em post futuros.

Mtodos de regex no js

O objeto regex possui dois mtodos: exec e test. J com string possui 4 mtodos: match, replace, search e split. Porm neste post vou me ater somente a 3 mtodos: test, match e replace.

test

Usado para verificar se uma regex da match com uma string. Ela retorna sempre valor boolean. Este mtodo ideal para fazer validaes como por exemplo validar se um email, telefone ou data esto corretos. Vejamos um exemplo validando nmeros de telefone:

match

Ele retorna um array, com as string que deram match com a regex. Se no houver valor, ele retorna null. Vejamos um exemplo procurando cep validos em um texto:

Vejamos acima que o ltimo nmero no foi pego no match, pois ele no um cep vlido.

replace

Usado para substituir strings que deram match por uma nova string. Segue um exemplo:

Podemos ainda manipular grupos. Vejamos um exemplo:

Um recurso legal do replace que podemos passar uma funo em vez da string de substituio. Isso ainda nos d mais possibilidades de alterao em algum texto que queremos substituir algo. Vejamos um exemplo:

Concluso

Chegamos ao fim, o estudo de regex muito interessante, sendo que possvel fazer muitas coisas em diferentes linguagens. Fiz uma extensa lista de diversos problemas resolvidos com regex, confira abaixo:

  • 18 aplicaes comuns de regex no dia a dia

Voc ainda pode testar suas regex de forma mais visual pelos sites:

  • Regex101
  • Regulex

Este meu primeiro post, espero que tenha ajudado. Vlws.

Referncias:

  • A guide to JavaScript Regular Expressions
  • 20 Small Steps to Become a Regex Master
  • Regex tutorial ? A quick cheatsheet by examples