Eu gosto muito de regex. Muito mesmo. Acho um assunto fascinante e já o estudei bastante. E uma das coisas que aprendi é que, mais importante do que saber usar, é saber quando NÃO usar. Pois é, por mais legal que seja, regex nem sempre é a melhor solução.
Por exemplo, para validar CPF e outros tipos de documento, não basta verificar o formato ("tantos dígitos, traço/ponto, etc"). Geralmente tais documentos possuem dígitos verificadores, e precisa de um cálculo para validá-los. E regex não faz cálculos, pois ela só lida com texto. Mesmo dígitos são tratados como meros caracteres, então somente com regex não dá para fazer tais cálculos. Se for para validar, é mais simples percorrer os caracteres um a um e ir fazendo o cálculo, e se no meio encontrar algum caractere inválido ou o cálculo não bater, já retorne o erro (exemplo).
Um uso que considero aceitável é se vc precisar extrair CPF's de um texto. Aí vc pode procurar por trechos que parecem um CPF (3 dígitos, ponto opcional, mais 3 dígitos, etc). Mas depois vai precisar validar os dígitos verificadores para ter certeza, claro. Agora, se vc só recebe uma string e precisa validar se ela é um CPF, aí um loop simples pelos caracteres me parece mais adequado.
O mesmo vale para outros tipos de dados que possuem regras de validação que vão além do formato. Um exemplo clássico são datas: os dias e meses possuem faixas de valores válidos (tem meses com 28, 29, 30 ou 31 dias, e 29 depende do ano ser bissexto - que por sua vez, envolve outro cálculo, etc). Sobre esse assunto, eu já escrevi aqui. Obs: até dá pra fazer uma regex que reconhece ano bissexto, mas é tão complicada que não vale a pena (é mais uma curiosidade, não use em produção).
Sobre o uso de regex para validar emails, tem algumas coisas aqui, aqui, aqui, aqui e aqui (este último link tem algumas opções no final, só não recomendo a última regex).
Resumindo, a lição dos links acima é que é muito difícil criar uma regex que aceite qualquer email válido (se quiser, aqui tem uma explicação bem detalhada sobre o assunto). Uma regex mais simples pode até "funcionar", mas também pode dar falsos positivos (pegar emails inválidos) - os links já indicados acima dão alguns exemplos.
No fim, a forma mais assertiva de validar um email é... mandando um email para o endereço indicado, geralmente com algum link/código de confirmação para a pessoa clicar. Aí vc não só valida o endereço, como também se ele está sendo usado por alguém que de fato quer usar o seu serviço. Claro que uma verificação mais básica ("tem letras e um @
") pode ser feita antes, mas é só um complemento, e não a validação definitiva.
Sobre telefones, aqui tem várias opções.
Sobre o segundo item:
Para definir expressões do tipo string, int, float em linguagens de programação, por exemplo: a regex
^[_a-zA-Z][_a-zA-Z0-9][ ][=][ ]*[0-9]+$
define uma expressão onde "x = 1" é inteiro e "x = a" não, pra que querer fazer uma nova linguagem isso é essencial.
Essa não é a forma ideal de validar expressões em linguagens de programação. Regex é a maneira mais ingênua e propensa a erros de resolver este problema. Ela até "funciona" com expressões mais simples, mas as linguagens geralmente usam outras ferramentas: definem uma gramática (geralmente BNF), criam o lexer, que por sua vez vai criar a AST (Abstract Syntax Tree), o parser vai analisar a sintaxe, etc.
O assunto é amplo e sugiro ler aqui, aqui e aqui para começar (sim, isso é só o começo).
Claro que algumas dessas ferramentas podem usar regex internamente, mas não da forma que vc fez. Sua regex é ingênua e não leva em conta vários fatores. Por exemplo, não reconhece números negativos. Muitas linguagens definem uma faixa de valores válidos para inteiros, a sua aceita uma quantidade ilimitada de dígitos. A expressão poderia ser x=1
(sem espaço depois do x
, mas sua regex obriga a ter sempre um). Aliás, curioso que antes do =
é obrigatório ter um espaço, mas depois pode ter zero ou vários.
Aproveitando, não precisa dos colchetes, poderia ser ^[_a-zA-Z][_a-zA-Z0-9] = *[0-9]+$
(sim, usar simplesmente o espaço funciona, os colchetes são desnecessários ali). Mas como já disse, os problemas dessa regex são outros. E não sei se foi erro de digitação, talvez tenha faltado um *
aí (deveria ser [_a-zA-Z][_a-zA-Z0-9]*
), porque da forma que está, o nome da variável só pode ter dois caracteres.
Sem contar que x = a
pode ser válido, caso a
seja outra variável que contém um valor inteiro. Enfim, como vc disse que isso é essencial pra quem quer fazer uma nova linguagem, acho importante dizer que regex é o menos essencial, tem uma série de outras coisas que precisa saber antes (veja nos links já citados).
E nem vou citar o fato de que muitas linguagens hoje em dia aceitam caracteres Unicode nos identificadores (ou seja, acentos, letras de outros alfabetos como o japonês, grego, árabe, etc). Claro que não é uma prática comum, mas se for criar uma linguagem, tem que levar isso em conta.
Para reconhecer strings, é mais complicado ainda, pois não basta pegar "tudo que está entre aspas", já que uma string pode ter aspas com escape, como por exemplo x = "abc \"entre aspas\" blabla"
. Teria que ser algo assim, por exemplo. E nem mencionei que analisar uma linha de cada vez nem sempre funciona, pois muitas linguagens aceitam statements que se prolongam por várias linhas. Ah, e se a declaração x = 1
estiver dentro de um bloco de comentários? Ex:
/*
várias linhas de código comentadas...
x = 1;
mais linhas comentadas...
*/
Fazer uma regex que ignora este bloco todo não é nada trivial. Boa sorte usando isso no seu código (é difícil para entender e manter).
Já um parser/lexer tradicional (usado pelos compiladores/interpretadores desde - ouso dizer - sempre) trata de todos esses casos sem problemas. Regex pode até "funcionar" para casos mais simples (avaliar uma ou poucas linhas de expressões bem simples), mas definitivamente não é a melhor solução para avaliar quaisquer expressões válidas em uma linguagem de programação.
Sobre o terceiro item, de fato pode ser útil, para fazer substituições em massa. Mas tem que tomar alguns cuidados, pois com regex é muito fácil fazer uma que pega tudo que vc quer, mas também pega o que vc não quer.
Por exemplo, no vídeo citado ele usa o atalho \w
para pegar o nome e sobrenome. Mas vale lembrar que \w
também pega dígitos, então se tivesse uma sequência de dígitos (que não faz parte de um nome), ela seria substituída também. Claro que no exemplo do vídeo não acontece porque não tem nenhum dígito no texto, mas é importante saber desses detalhes para não ser pego de surpresa. Por exemplo, se tivesse dígitos no texto, eu seria mais cuidadoso e não usaria \w
.
Por fim, não me entenda mal. Como eu já disse, gosto muito de regex. Mas eu não uso pra tudo, pois aprendi que nem sempre ela é a melhor solução. E mesmo quando é, tem que lembrar que em geral regex é mais lenta. Isso porque toda regex é compilada (sim, isso mesmo, compilada!), e isso não tem nada a ver com a compilação do seu código: a engine de regex tem um compilador à parte (que não é o mesmo da linguagem que vc usou), que analisa a expressão e cria uma estrutura interna em memória.
Ou seja, enquanto a regex ainda está compilando, o loop que valida os dígitos verificadores do CPF já retornou :-)
Claro que hoje em dia os computadores estão tão rápidos que essa diferença é imperceptível, mas talvez se for processar uma grande quantidade de itens, já comece a fazer diferença. Cada caso é um caso, o importante é saber os prós e contras, analisar o contexto e só então decidir. O que não pode é sair usando pra tudo (e isso vale pra qualquer coisa em computação, não só regex).