Uma expressão regular é uma forma comum e concisa de representar algum tipo de padrão em texto. Você pode usá-las, por exemplo, com o recurso de “Localizar e Substituir” para fazer alterações rapidamente em um grande volume de dados. Imagine que você tem um documento com milhões de registros de diferentes tipos e deseja buscar todas as datas contidas nele.
Um modo de fazer isso seria usar a expressão regular :
[0-9]{2}[-|\/]{1}[0-9]{2}[-|\/]{1}[0-9]{4}
Assim, você encontraria qualquer uma sequência de números e texto no formato DD-MM-YYYY, por exemplo (neste caso, encontraria mesmo “datas” inválidas, como 32-01-2019). Uma linha e já não é mais necessário percorrer milhares de páginas para obter a informação que se busca.
Pareceu confuso? Não tem problema. Vamos dar uma olhada no básico sobre expressões regulares e depois voltamos neste exemplo, ao final do tutorial.
Você pode aplicar isso em uma variedade de aplicações e linguagens, seja pesquisando em um documento, fazendo operações de ‘Localizar e Substituir’ ou limpando um conjunto de dados. Muitas linguagens de programação e editores de texto/planilha permitem o uso de expressões regulares, de modo que você pode aplicá-las em uma enorme gama de situações. As sintaxes podem diferir levemente de acordo com a linguagem ou programa em uso, mas aqui neste tutorial vamos te passar o básico para você começar a usar Regex no seu dia a dia.
Algumas dicas iniciais
Por mais complicado que expressões regulares possam parecer, elas são todas compostas de partes menores que são usadas para descrever um determinado padrão. Entender estas unidades é simples, porém, antes de começar a aprender a linguagem, tenha em mente algumas coisas:
– Lembre-se sempre que Regex por padrão é case-sensitive: ou seja, faz diferença ESCREVER EM MAIÚSCULAS ou em minúsculas.
– Alguns caracteres em expressões regulares possuem significados especiais. Outros, não. Para dar um significado especial (utilizá-lo como um filtro, por exemplo) a um caractere normal ou para usar um caractere especial (que funciona como um filtro) com significado literal, usamos a barra invertida \ antes deles.
Tudo isto vai ficar mais claro com os exemplos abaixo. Neste tutorial introdutório, vamos dar uma olhada então em alguns tipos de caracteres e suas respectivas funções em expressões regulares.
Na primeira coluna, você tem uma descrição do tipo de caractere. Na segunda, um exemplo de busca utilizando estes caracteres, mostrando em sequência o que esta busca retornaria (terceira coluna) e o que ela não retornaria (quarta coluna). Por fim, explicamos o que está por trás disso tudo.
Você também pode usar este site para testar os comandos abaixo
Tipo | Busca por.. | Retorna… | Não retorna… | Por quê? |
Letras e números | gato | gato | GATO Gato grato | Letras e números não possuem significado especial, ou seja, referem-se a eles próprios. A letra “a” refere-se apenas à própria letra minúscula “a”; 3 refere-se ao algarismo “3”, etc. Ao buscarmos por “gato”, o retorno será exatamente os caracteres “g”, “a”, “t”, “o” nesta sequência e em minúsculas. |
Números | \d OU [0-9] | 0123456789 | um zero ou qualquer _ outro caractere alfabético ! | Com a barra invertida antes, o “d” “escapa” do seu sentido literal e passa a significar qualquer dígito de 0 a 9 |
Curinga (ponto) | . | Todos caracteres, exceto quebras de linhas | Um ponto (.) tem um significado especial: ele reconhece todos os caracteres em uma linha. Ao ser precedido da barra invertida (\.), ele apenas reconhece o caractere ponto, então ele se torna literal, um caractere sem significado especial. | |
Curinga (ponto) | BRA.IL | BRASIL BRAZIL BRAKIL | BRASIIL BRZIL | O ponto (.) também pode ser usado dentro de expressões, servindo como curinga para qualquer caracter |
Legal, não é? Agora, vamos ver as classes de caracteres.
Tipo | Busca por.. | Retorna… | Não retorna… | Por quê? |
Classes de caracteres | Bra[sz]il | Brasil Brazil | BRASIL Basil Bravil | Você pode especificar uma classe de caracteres (uma lista de caracteres que se equiparam) ao rodeá-los com colchetes. Outro exemplo: [aeiou] – com isso buscamos qualquer vogal |
Intervalo alfabético | [A-Za-z]. | Qualquer letra (maiúscula ou minúscula) | 0123456789 !_@#$%&() | Usando o hífen podemos definir um intervalo numérico, como no exemplo anterior, mas também alfabético |
Espaços em branco | \s | Espaços em branco, como space e tab | 0123456789!@_$ | O “\s” te permite buscar caracteres “invisíveis” como espaço e tab |
Intervalo alfabético com caractere extra | [a-z_] | Qualquer letra minúscula ou subtraço (underscore) | 0123456789 | No exemplo, dentro dos colchetes, o “a-z” é um elemento a ser buscado, assim como o subtraço |
Todos caracteres de palavras | [A-Za-z_] | Retorna todos os caracteres de palavras (letras e o subtraço). | 0123456789 !_@#$%&() | Tal como no exemplo acima, usamos o hífen para definir um intervalo (todas as letras maiúsculas e minúsculas entre A e Z, além do subtraço) |
Negação | [^aeiou] | Qualquer caractere exceto as cinco vogais | brsl | Se um acento circunflexo (^) for o primeiro caractere entre colchete, a classe inteira será negada Se você quiser que sua classe inclua um acento circunflexo literal (em vez de negar todo o resto que esteja lá), você pode usar o escape nele (\^) ou colocá-lo em outro lugar que não seja o começo; |
Por fim, vamos ver quantificadores e grupos. Você pode cercar uma parte de uma expressão regular por parênteses para tratá-la como uma unidade.
Tipo | Busca por.. | Retorna… | Não retorna… | Por quê? |
Conjunção | URSS|RUSSIA | URSS RUSSIA | Ucrânia PRUSSIA | Use o caractere pipe (|) para dar duas opções para a conjunção |
Encapsulamento | (REINO UNIDO)|(PAÍS DE GALES) | REINO UNIDO PAÍS DE GALES | REINOUNIDO REINO | Os parênteses permitem encapsular as regras do seu interior a fim de tratá-las como uma coisa só |
Caractere opcional | impostos? | imposto impostos | empostos impostoss | Torna opcional o último caractere antes do ponto de interrogação; ou seja, no exemplo, o caractere “s” pode aparecer zero ou uma vez |
Asterisco | impostos* | imposto impostos | impstossss | Já o asterisco permite buscar por zero ou mais ocorrência do caractere especificado anteriormente |
Sinal de mais | impostos+ | impostos impostossss | imposto | Com o sinal de mais, buscamos pelo menos uma ocorrência do caractere ou grupo especificado anteriormente (no exemplo, a letra “s”) |
Sinal de chaves | vacu{2}m | vacuum | vacum | As chaves servem como multiplicadores, indicando quantas vezes o caractere ou grupo precedente deve aparecer; no exemplo, para dar “match” a letra “u” deve aparecer duas na palavra especificada |
Mas como isso funciona na prática?
Se você for testar a sequência abaixo em algum editor de texto, lembre-se de conferir se a opção de busca por expressão regular está ativada, caso contrário o software irá interpretar os caracteres literalmente. Vamos ver agora como colocar tudo que abordamos isso de forma integrada em um exemplo real.
Lembra do nosso primeiro exemplo? Mostramos uma expressão regular que identificada o padrão de datas no formato DD-MM-YYYY.
[0-9]{2}[-|\/]{1}[0-9]{2}[-|\/]{1}[0-9]{4}
Vamos decompor a sequência em suas partes menores:
[0-9] | Significa qualquer caractere numérico entre 0 e 9. Ou seja: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 |
{2} | Com este quantificador, dizemos que o padrão que buscamos precisa repetir duas vezes a descrição anterior: [0-9] |
Com isto identificamos os dígitos do dia. Repare, no entanto, que o padrão iria encontrar datas “falsas” tais como 88/02/2018 e, por outro lado, não encontraria datas reais que não obedeçam ao formato descrito, por exemplo: 6/03/1988. Neste segundo exemplo, a data não seria localizada pois falta um dígito (zero) no campo “dia”. Mas vamos em frente:
[-|\/] | Aqui, estou selecionando os caracteres que servem como separador da minha data. Neste caso, escolhe o hífen, a barra vertical e o barra (“/”). Repare que a barra precisa ser escapada com uma barra invertida “\” antes para ser interpretada corretamente. Visualmente, a junção da barra invertida com a barra normal ( \/ ) lembra a letra V, mas não há esta letra na sequência ao lado. |
{1} | Defino que o caractere anterior deve aparecer uma única vez |
Com isto, definimos que o padrão anterior aceita três tipos de separadores, de modo que todas estas diferentes formas de escrever a mesma data seriam encontradas:
03/06/1980
03-06-1980
03|06|1980
Vamos rever nossa fórmula?
[0-9]{2}[-|\/]{1}[0-9]{2}[-|\/]{1}[0-9]{4}
A mesma estrutura já descrita é reutilizada no mês. Para identificar o ano, a única diferença é o número definido para o quantificador: ao invés de um número com 2 caracteres, busco agora um número com formato de 4 caracteres para assim atender ao padrão DD-MM-YYYY.
Saiba mais
Quer se aprofundar mais? Confira esta lista de links especiais que separamos para você:
Recursos didáticos
- RegExr: http://regexr.com/
- Página da Web que permite testar diferentes expressões regulares. Anota cada parte da sua expressão e fornece informações úteis sobre cada correspondência
- The Bastards Book of Regular Expressions: http://regex.bastardsbook.com/files/bastards-regexes.pdf
- Material focado no trabalho com padrões comuns em textos
- Regex Crossword: https://regexcrossword.com/
- Jogo para te ajudar a praticar e interpretar expressões regulares
- Cheatsheet: http://www.cbs.dtu.dk/courses/27610/regular-expressions-cheat-sheet-v2.pdf
- “Colinha” com usos comuns de Regex
- RegexBuddy: https://www.regexbuddy.com/manual/RegexBuddy.pdf
- Manual baseado no programa homônimo (pago, para Windows) que ensina a lidar com Regex
- Regular Expression – The complete tutorial: https://www.princeton.edu/~mlovett/reference/Regular-Expressions.pdf
- Tutorial sobre Regex com exemplos
Editores
- Emacs: https://www.emacswiki.org/emacs/RegularExpression
- Notepad++: http://docs.notepad-plus-plus.org/index.php/Regular_Expressions
- Sublime Text: http://bit.ly/st-regexp
- TextWrangler: https://gist.github.com/ccstone/5385334
Regex em linguagens
- Bash: http://tldp.org/LDP/abs/html/regexp.html
- JavaScript: https://bit.ly/js-regexp
- PHP: http://php.net/manual/en/book.pcre.php
- Python: https://docs.python.org/3.6/library/re.html
- Ruby: http://ruby-doc.org/core-2.4.0/Regexp.html
Tem alguma diferença entre o regex descrito aqui e o gnu utilizado no grep por exemplo ?
trechos como foo2( com regex [o]{2} funciona no site de práticas atual e no grep não
Oi Daniel, existem várias implementações diferentes de Regex. Então, sim, a sintaxe pode variar dependendo de onde você vai rodar.
No manual do grep, por exemplo, vemos que:
” grep understands three different versions of regular expression syntax: “basic” (BRE), “extended” (ERE) and “perl” (PCRE)”
Já no site regexr.com, temos:
“While the core feature set of regular expressions is fairly consistent, different implementations (ex. Perl vs Java) may have different features or behaviours. RegExr currently supports JavaScript RegExp executed in your browser and PCRE via PHP”
Espero ter ajudado
Parabéns pelo artigo – muito útil para o dia a dia da programação