Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
September 15, 2022 10:35 pm GMT

Expresses Regulares IV - as trs regras da regex I - backtracking

Alguns anos atrs eu comecei a falar que h trs regras para se usar expresses regulares

  1. no use regex
  2. reconsidere se voc precisa usar regex
  3. conhea sua engine

Pode parecer engraado eu usar duas regras para desencorajar o uso de regex sendo que eu estudo isso e estou inclusive escrevendo uma srie de artigos dedicados a ensinar como us-la, mas eu vou explicar.

A primeira e a segunda regra so na verdade a mesma e esto duplicadas para efeito de nfase.

Quando comeamos a aprender regex (e at quando j sabemos h um tempo), ficamos tentados a usar para solucionar qualquer problema. Da fazemos coisas como essa para validar uma data.

/^(?:([0-1])|(2)|(3))(?(1)[0-9])(?(2)(?:([0-8])|(9)))(?(3)[0-1])\/(?:(01|03|05|07|09|11)|(04|06|08|10|12)|(02))(?(3)(?(8)(?!)))\/\d*(?:(04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)|(\d\d))(?:(00)|(04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)|\d{2})(?(2)(?(5)(?(8)(?(11)(?(9)|(?!))|(?(12)|(?!))))))/

(podem test-la, a propsito https://regex101.com/r/aqEsf1/1)

Essa atrocidade de regex valida no somente o formato da data (que precisa ser dd/MM/yyyy), mas tambm valida se a data vlida. Dia 31 de setembro no validada. Dia 29 de fevereiro de 2021 no validada. Eu tenho um certo orgulho dessa regex, francamente (sim, eu que fiz).

Porque no a usamos ento? Eu apresento dois motivos.

O primeiro mais bvio: essa regex incompreensvel e um pesadelo de se mexer. Se houver algum bug nela, qualquer tentativa de mud-la ser muito custosa.
O segundo no to bvio, mas deve ser simples de entender: essa regex muito custosa para a engine.

Para explicar, precisamos falar sobre como a engine funciona internamente. Apertem os cintos e vamos l!

Funcionamento interno das engines de regex

Embora cada engine tenha uma particularidade, podemos divid-las em duas categorias: engines text-directed e regex-directed.
No falaremos de engines text-directed aqui, pois seu funcionamento trivial porque no existe backtracking e as engines mais usadas so as regex-directed. Vamos a elas ento.

As engines regex-directed, chamadas a partir de agora somente de engines, funcionam basicamente da seguinte forma:

  1. Enquanto houver tokens na regex, pegue o prximo token
  2. Tente dar match com o prximo caracter da string
  3. Se houver match, avance para o prximo token da regex e o prximo caracter da string
  4. Se no, volte at uma posio anterior da regex para testar um outro caminho por ela (esse o backtracking)

Vamos de exemplo. Vamos aplicar a regex /<.*?>/ no texto <span>Teste</span>.

  1. Enquanto houver tokens na regex, pegue o prximo token (<)
  2. D match com o prximo caracter da string (<)1 Houve match, ento avana para o prximo token da regex (.*?) e prximo caracter da string (s)
  3. O token .*? o quantificador lazy que vai dar match no mnimo possvel para que a regex seja vlida. A primeira tentativa de um match sem tamanho (match em '').
  4. D match, ento avana para o prximo token da regex (>) e o prximo caracter da string (s).
  5. No d match, ento retorna a regex pro token anterior (.*?)
  6. D match, pois . d match em qualquer caracter (exceto quebra de linha), ento avana para o prximo token da regex (>) e o prximo caracter da string (p).
  7. No d match, ento retorna regex (.*?).
  8. .*? deu match em s antes, mas agora precisa dar match em sp. Tudo bem, pois . d match em qualquer caracter (exceto quebra de linha) e * d match em mais de um caracter.
  9. D match, ento avana regex (>) e string (a).
  10. No d match. Isso vai se repetir at a regex encontrar na string o caracter >. Nesse caso, ela vai dar match e retornar ok.

Segue um esquema tirado da aplicao RegexBuddy para explicar melhor.

Beginning match attempt at character 0<< ok< backtrack<s<s backtrack<sp<sp backtrack<spa<spa backtrack<span<span backtrack<span>Match found in 11 steps

(espaos adicionados por clareza)

Dessa maneira, possvel notar que h as engines vo e voltam na string at encontrar uma soluo para a regex. Vamos pegar o diagrama do RegexBuddy para uma data e aquela regex.

Beggining match attempt at character 0ok111121212 ok12 ok12 ok12 ok12/12/012/0 backtrack12/012/0 backtrack12/012/0 backtrack12/012/0 backtrack12/012/0 backtrack12/ backtrack12/ backtrack12/012/0 backtrack12/012/0 backtrack12/012/0 backtrack12/ backtrack12/ backtrack12/ backtrack12/012/0212/0212/0212/02 ok12/02 ok12/02/12/02/ backtrack12/02/ backtrack12/02/ backtrack12/02/ backtrack12/20/212/02/2012/02/2012/02/2012/02/20012/02/200 backtrack12/02/20 backtrack12/02/20012/02/200 backtrack12/02/20012/02/200 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/20 backtrack12/02/200312/02/200312/03/2003 ok12/03/2003 okMatch found in 81 steps

Um tanto mais complexo que a soluo preferida, que em Java seria algo como:

Date date = new Date('12/02/2003');

Pois a implementao do Java j testa se a data vlida ao instanciar o objeto.
importante lembrar que nenhuma engine de regex tem informaes semnticas sobre o texto. Enquanto o Java tem como saber que 12 na data dia e 2003 ano, a engine de regex s entende texto.

A mesma coisa para email. Em vez de usar uma regex monstruosa como a seguinte:

(?:(?:\r
)?[ ])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*))*@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)*\<(?:(?:\r
)?[ ])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*(?:,@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*)*:(?:(?:\r
)?[ ])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*))*@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*\>(?:(?:\r
)?[ ])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)*:(?:(?:\r
)?[ ])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*))*@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)*\<(?:(?:\r
)?[ ])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*(?:,@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*)*:(?:(?:\r
)?[ ])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*))*@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*\>(?:(?:\r
)?[ ])*)(?:,\s*(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*))*@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)*\<(?:(?:\r
)?[ ])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*(?:,@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*)*:(?:(?:\r
)?[ ])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r
)?[ ]))*"(?:(?:\r
)?[ ])*))*@(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*)(?:\.(?:(?:\r
)?[ ])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r
)?[ ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r
)?[ ])*))*\>(?:(?:\r
)?[ ])*))*)?;\s*)

uma soluo mais simples mandar um email para o endereo. Se estiver vlido, o email chegar. Para auxiliar o usurio a preencher o formulrio, basta verificar com essa regex

.*@.*\..*

ou algo parecido.

A terceira regra ser tratada no prximo artigo. Abraos.


Original Link: https://dev.to/feministech/expressoes-regulares-iv-as-tres-regras-da-regex-i-backtracking-16j1

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To