Executando verificação de segurança...
20

Regex para seres humanos 🤖

Olá ✌,
nesse breve artigo quero trazer algumas pequenas coisas que me ajudaram e podem facilitar o seu entendimento no assunto... como não sou o dono da verdade, quero que você comente o que achou do post e suas sugestões de alterações!

Introdução

Regex (Expressões regulares) são amplamente utilizados para verificar, padronizar e até mesmo extrair uma parte de uma string. Ou seja, com ele podemos fazer 3 ações, buscar, validar e substituir

OBS.: Cada linguagem de programação lida com o regex de forma diferente, este breve artigo é mais voltado ao JavaScript

Sua Estrutura 🏛️

  • Primeiro temos os separadores /, ~, @, ;, %, `, #

    os separadores delimitam o início e o fim de um regex, dependendo da linguagem de programação devemos utilizar um ou outro, em algumas não devemos utilizá-los


  • \w - Todos os caracteres de a-z, A-Z, 0-9 e _
  • \W - Tudo que não for letra nem número
  • \d - Número decimal 0-9
  • \D - Qualquer coisa que não seja um número
  • \X - Qualquer carácter unicode
  • + - Sequencia, como, por exemplo, \d+ é uma sequência de dígitos
  • * - Sequencia de caracteres ou nada
  • | - Ou
  • [0-9]{4} - Determina 4 dígitos de 0 a 9
  • [0-9]{2,4} - Determina de 2 a 4 dígitos de 0 a 9
  • ^ ou \A - Início de string
  • $ ou \Z - Fim de string

  • Após o fim do regex temos as flags:
    • g Global - busca em toda a cadeia de caracteres o padrão desejado como é possível ver no exemplo a seguir:

      Regex: /a/g
      acasa é amarela

    • m Multiline - usando-o os símbolos ^ e $ correspondem respectivamente ao início e fim de cada linha

      Regex: /^casa$/m
      casa
      é amarela, casa

    • i Insensitive - não diferencia letras maiúsculas com minúsculas

      Regex: /a/i
      Acasa é amarela

      Regex: /a/gi
      Acasa é amarela

    • s Single Line - faz a cadeia de caracteres ter tratada como se fosse em uma única linha

      Regex: /a.*a/is
      A
      casa é amarela

      Regex: /a.*a/i
      A
      casa é amarela

    • u Unicode - os intervalos de [a-z] serão tratados todos os caracteres unicodes

      Regex: /\w/giu
      A casa é amarela

      Regex: /\w/gi
      A casa é amarela

Alguns exemplos de Regex 📑

  • Email: /^[a-zA-Z0-9-.+]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

    [email protected]

  • Slug: /^[a-z0-9-]+$/

    regex-23

  • Username: /^[a-z0-9-_]+$/

    pedro_06-2022

Mande o seu Regex que você mais utiliza e que sentiu falta, caso você queria se aprofundar mais no regex recomendo que leia e utilize a ferramenta regex101!

Carregando publicação patrocinada...
4

Muito bom, só gostaria de acrescentar uns detalhes...

Acho importante falar que existem diferenças entre as linguagens, cada uma implementa regex de um jeito e o que vale pra uma pode não funcionar em outra. Claro que muitas coisas funcionam igual, mas tem várias diferenças também.

Por exemplo, os separadores (que também podem ser chamados de delimitadores) que vc citou valem pra PHP e Perl, mas em JavaScript só se usa as barras (/regex aqui/). Em outras linguagens, como Java, Python e C#, se passa uma string contendo a regex, mas sem os delimitadores (ex: em Python se faz apenas re.search('[a-z]', texto) - se usar re.search('/[a-z]/', texto), ele vai procurar pelas barras no texto).

Muitas linguagens suportam Unicode por padrão, então atalhos como \w consideram todas as letras definidas pelo Unicode, o que inclui vários alfabetos como o japonês, coreano, árabe, cirílico, etc. E também considera os dígitos Unicode (não é só de 0 a 9, tem vários outros caracteres).

Em Python 3, por exemplo, o \w já suporta Unicode por padrão. Em PHP precisa usar a flag u, no JavaScript essa flag não adianta e precisa de Unicode property escapes (ex: /\p{L}/u para letras), em Java a flag que habilita o modo Unicode é Pattern.UNICODE_CHARACTER_CLASS, etc. Cada linguagem pode ou não suportar Unicode, que pode ou não ser o default, e pode ou não ter modos de configurar.

Um detalhe importante que muita gente esquece - inclusive eu - é que o \w (minúsculo) também considera o caractere _. Então \W (maiúsculo) na verdade é tudo que não for letra, número, ou _.

Quanto as flags, também tem diferenças. A flag g, por exemplo, é coisa do JavaScript. Em outras linguagens o normal é procurar todas as ocorrências, enquanto outras fornecem opções diferentes para cada caso. Por exemplo, em Python usa-se match ou search para buscar uma ocorrência e findall ou finditer para buscar todas. Em PHP usa-se preg_match para a primeira ocorrência e preg_match_all para todas, em Java faz-se um loop no objeto Matcher (controlando a quantidade de vezes, caso não queira todas) e assim por diante. Ou seja, nessas linguagens não precisa da flag g.

E a forma de ligar as flags também muda. Nas linguagens que possuem delimitadores (JavaScript, PHP, Perl), coloca-se no final (/\w/img por exemplo), em outras coloca-se como parâmetros (exemplo em Python: re.compile(r'\w', re.I) para passar a flag case insensitive).

Já o \X é mais do que "qualquer caractere Unicode". Na verdade ele corresponde a um grapheme cluster. De forma bem resumida, muitos caracteres na verdade são formados por vários code points que juntos representam uma coisa só. Um exemplo moderno são as sequências de emojis, mas muitos idiomas possuem caracteres que só podem ser representados por mais de um code point - leia aqui, aqui e aqui para mais informações.

O problema é que nem todas as engines suportam o \X, e mesmo quando suportam, ele pode não reconhecer todos os grapheme clusters, pois depende da versão do Unicode suportada.

Quanto a ^ e $, que indicam o início e fim da string, vale lembrar que muitas engines possuem a flag multiline. Quando habilitada, esses atalhos também pegam o início e fim de uma linha. Já o \A e \Z pegam só o início e fim da string, independente da flag estar habilitada.

E algumas engines também suportam o \z, que tem diferença quando a string termina com uma quebra de linha (\Z vai até a quebra de linha e não a inclui no match, \z vai até o final e inclui a quebra de linha).

1

Muito obrigado pela sua contribuição 🖖, nossa quanto conteúdo massa que você está agregando a esse post...

Irei fazer algumas alterações para deixar mais claro!

4

Sobre os exemplos, alguns comentários:

A regex de email considera que coisas como [email protected] são emails válidos.

Regex pra email, que não dê esses falsos positivos, é bem mais complicado do que parece. Claro que a regex em questão pega emails válidos, o problema é que também pega muitos inválidos...

Para o slug, a regex considera que uma string vazia é um slug válido (porque o * significa "zero ou mais caracteres", então se não tiver nenhum também serve). Se não era essa a intenção, pode trocar por + (um ou mais caracteres) ou então usar quantidades específicas de acordo com cada caso (ex: {5,} para ter no mínimo 5 caracteres, {5,20} para ter entre 5 e 20, etc).

E na regex do username, acho que faltou um quantificador. Da forma que está (^[a-z0-9-_]$) ele pega somente um caractere.

1
1

Complementando, a regex do username considera que _ é um username válido. E tanto o slug quanto o username consideram que um valor com somente dígitos é válido (ex: 1234).

Dependendo do caso, isso pode ou não fazer sentido.

O problema de regex é esse, não é tão difícil fazer uma que pegue os casos válidos, mas é mais complicado fazer com que também exclua os inválidos.

2
2

Cara, a minha vida de dev mudou completamente depois que eu aprendi regex. Tive uma época em que trabalhei muito com arquivos TXT e regex me salvava de mais!! Só acho uma pena que nos cursos que fiz (Técnico e Bacharelado) não tive uma disciplina dedicada a elas, tive que aprender sozinho!

Esse livro aqui me ajudou de mais!!

1

Um livro que gostei bastante foi esse.

Mas ele é bem denso, até hoje não consegui absorver tudo. Mas meu conhecimento em regex aumentou muito.

1
1
1
1
1

Wow! leve embora minhas tabcoins! Até salvei aqui pra servir se consulta. Regex é aquele negocio que voce faz varias vezes, mas sempre esquece quando tem que fazer de novo rs

1

Como que a gente ainda não tem um botão "salvar" para poder deixar esse conteúdo guardado pra sempre?

Vou ver se já tiveram essa ideia no repositório.

1

Muito bom, parabéns.
Uma dica que posso dar que me ajudou, é pegar regex de bibliotecas de código aberto e avaliar a mesma, como exemplo Joi que usa nesse projeto.

1
1
0
0