rg

Regex é legal 2


Olá galera, tudo bem?!

Hoje vou abordar um assunto no qual gosto, Regular Expressions, também conhecido como Regex, e na minha opinião não é um bixo de sete cabeças. É comum eu ler comentários de colegas de profissão dizendo: “Escreva uma vez, não entenda nunca mais“, e na minha humilde opinião não é por ai. Regex é uma linguagem na qual podemos aprender, creio que esses casos que as pessoas não entendem nunca mais uma regex, é pelo simples fato de não conhecer a linguagem e simplesmente:

  1. Pesquisar
  2. Copiar e Colar
  3. Resolver problema
  4. Não entender a solução.

Regex possui uma sintaxe como qualquer outra linguagem e se não aprendermos ela, realmente nunca iremos entender uma regex, enfim a culpa é devido a incompetencia do desenvolvedor.

Definição da wikipedia

Em ciência da computação, uma expressão regular (ou o estrangeirismo regex, abreviação do inglês regular expression) provê uma forma concisa e flexível de identificar cadeias de caracteres de interesse, como caracteres particulares, palavras ou padrões de caracteres. Expressões regulares são escritas numa linguagem formal que pode ser interpretada por um processador de expressão regular, um programa que ou serve um gerador de analisador sintático ou examina o texto e identifica partes que casam com a especificação dada.

Exemplo real

Certa vez vi uma expressão regular, que de acordo com o autor dela servia para identificar urls que não possuem o “www.”, por exemplo:

  • http://facebook.com
  • https://gmail.com

A regex em questão era a seguinte:
^((http|https)://[^www]).*$

Porem existe uma problemática nessa url, ela não faz exatamente o que ela foi incumbida a fazer, em um caso com uma url assim: http://wordpress.com, essa regex retornaria falha, mas não temos o www. então a regex está errada. E o pior de tudo é que ela funciona em muitos outros casos, como os citado acima.

Vamos analisar parte por parte dessa regex.

Primeira parte => ^((http|https)://

Essa parte indica que queremos que nossa string comece com http:// ou https://.

Nós podemos melhorar essa regex dessa maneira:

^https?://

Quando usamos parenteses em uma regex, nos estamos definindo um grupo, e quando temos o pipe(|) dentro do grupo, significa que temos a condição “OU” , sendo assim, http ou https. Mas o proposito da regex não faz necessario termos esse grupo, então simplificamos ele, e tivemos o mesmo resultado trocando todos os parenteses e o pipe por um simples “s?“. O simbolo de interrogação(?) indica que a regra anterior é opcional, no qual a regra anterior é um “s” apos http.

Segunda parte => [^www]

É aqui onde está o perigo! Essa regex é semelhante a essa:

[^w]

Essa regex diz que não podemos ter um “w” depois da regra anterior, que é o a existência do http:// ou https://. Quando usamos os colchetes “[]”, estamos definindo uma cadeia de caracteres que são ou não aceitos, quando eles não são aceitos usamos o simbolo circunflexo “^” para negar a existência deles, segue alguns exemplos:

  • ^[0-9]+$ => Permitimos somente números na string.
  • ^[A-Za-z]+$ => Permitimos somente letras maiúsculas ou minusculas.
  • ^[\w]+$ => Permitimos somente letras(maiúsculas e/ou minusculas) e/ou números.
  • ^[^0-9]+$ => Permitimos qualquer caractere que não seja um número, o que não quer dizer que essa regex é semelhante a regex acima, elas podem resultar em um resultado igual.

Como vemos nesse ultimo exemplo podemos dizer que duas regex dão um mesmo resultado pelo fato de não conhecermos a linguagem, como vimos na primeira parte, temos 2 regex que dão o mesmo resultado, repetindo novamente:

^((http|https)://) == ^https?)://

Mas e agora, como fazer uma regex que informe se o http(s):// não é seguido de “www.”.

Para chegarmos ao nosso objetivo vou usar o chamado lookahead um recurso brilhante das expressões regulares. O lookahead nada mais é que essa determinada regra não deve existir apos a regra anterior, sendo assim a nossa regex ficaria dessa forma:

^https?://(?!www[.]).+$

Para atingir nosso real objetivo, trocamos [^www] por (?!www[.]), com isso, aplicando na regex antiga ficaria assim:

((http|https)://[^www]).*$

Que retorna o mesmo resultado para regex anterior a ela, mas o problema dessa regex é como um código ruim com variáveis não utilizadas que nesse caso é o excesso de parenteses e a existência ou não do “s” que ao invés de usar grupo pode facilmente ser substituída pelo caractere opcional usando o “?”.

Observação

Como vimos na definição da wikipedia, a regex é interpretada por um processador, e existem diferente tipos de processadores de regex, o processador de regex do .NET não é igual ao processador em Javascript, mas graças ao POSIX que é o padronizador de expressoes regulares, essa preocupação é absurdamente reduzida, enfim para ilustrar uma situação que isso acontece temos uma regex com um grupo nomeado:

^\d{2}/\d{2}/(?<ano>\d{4})$

Em C# essa expressão regular é aceita, e inclusive podemos acessar esse grupo de forma fácil:

[csharp]string strRegex = @"^\d{2}/\d{2}/(?<ano>\d{4})$";
Regex myRegex = new Regex(strRegex);
string strTargetString = @"25/02/1800";

foreach (Match myMatch in myRegex.Matches(strTargetString))
{
if (myMatch.Success)
{
Console.WriteLine(myMatch.Groups["ano"].Value);
}
}[/csharp]

Já em javascript, a sua execução retornaria um erro, já que ele não aceita grupos nomeados

[javascript]
/^\d{2}/\d{2}/(?<ano>\d{4})$/.test("25/02/1800")
[/javascript]

SyntaxError: Invalid regular expression: /^\d{2}\/\d{2}\/(?<ano>\d{4})$/: Invalid group

É isso pessoal!


sobre Alberto Monteiro

Desenvolvedor no Grupo Fortes, cuja principal área de conhecimento são em tecnologias Microsoft, como Windows Forms / Services, WPF, ASP.NET(MVC/WEB API), Windows Phone, EF. Gosta de sopa de letrinhas(SOLID, DDD, TDD, BDD, IoC, SoC, UoW), possui aplicações de Windows Phone publicadas no marketplace, já contribuiu no jQuery UI. Atualmente trabalha com ASP.NET MVC / Web API, Windows Azure, Amazon AWS, jQuery/UI, Knockout, EF, Ninject, AutoMapper, Restfulie, SignalR, KendoUI.

  • Fernanda Brasiliense

    Olá Alberto tudo bem?
    Estou aprendendo expressão regular e ainda tenho algumas dúvidas…
    Utilizo o CrazyEgg para algumas análises e ele trabalha com Regex para URL, meu problema é o seguinte.

    Tenho uma URL fixa http://www.blabla.com.br/brubru
    A partir dessa principal pode-se ser direcionado para outras páginas …

    O que eu preciso é montar uma Regex que não tenha a expressão “zero-resultado” e que tenha a expressão “c-” pode me ajudar?

    🙂

    Desde já agradeço!!

  • AlbertoMonteiro

    Eu não entendi muito bem o seu caso, se você quiser me enviar por email explicando melhor o caso, e me dar um exemplo do que a regex vai aceitar e recursar seria otimo. Meu email para contato é o alberto.monteiro[at]live.com(troca o [at] por @)
    Só vou ter disponibilidade para te ajudar apos as 19h(sem horário de verão)