An Interest In:
Web News this Week
- April 2, 2024
- April 1, 2024
- March 31, 2024
- March 30, 2024
- March 29, 2024
- March 28, 2024
- March 27, 2024
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
- no use regex
- reconsidere se voc precisa usar regex
- 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:
- Enquanto houver tokens na regex, pegue o prximo token
- Tente dar match com o prximo caracter da string
- Se houver match, avance para o prximo token da regex e o prximo caracter da string
- 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>
.
- Enquanto houver tokens na regex, pegue o prximo token (
<
) - 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
) - 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 ''). - D match, ento avana para o prximo token da regex (
>
) e o prximo caracter da string (s
). - No d match, ento retorna a regex pro token anterior (
.*?
) - 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
). - No d match, ento retorna regex (
.*?
). .*?
deu match ems
antes, mas agora precisa dar match emsp
. Tudo bem, pois.
d match em qualquer caracter (exceto quebra de linha) e*
d match em mais de um caracter.- D match, ento avana regex (
>
) e string (a
). - 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
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To