Uso expressões regulares há tantos anos, que hoje para mim é muito natural, diria até automático, ficar compondo uma regex na cabeça, nas mais diversas (e inúteis) situações. Por exemplo, se estou relaxado lendo um artigo e em seu texto aparece alguma repetição, pequena variação ou formato numérico, me pego pensando nos metacaracteres que casariam aquilo.
Tá, é bizarro, eu sei :)
Nos artigos anteriores do blog, falei sobre os equipamentos da Apple e várias vezes precisei citar os três brinquedos pretos: iPod, iPad e iPhone. Ao escrever estes nomes, um alerta apita aqui dentro: Epa! Repetição e variação detectados!
Compor uma expressão regular que case os três nomes não é difícil. Uma primeira alternativa, mais simplista, seria usar o metacaractere ou para fazer a lista de palavras permitidas:
iPod|iPad|iPhone
A barra vertical indica que esta expressão casa iPod ou iPad ou iPhone. Simples, não? Fácil de ler e entender. Mas podemos tornar esta expressão menor e mais eficiente.
O segredo para fazer uma boa expressão é saber identificar padrões. Ao olhar com atenção para estas três palavras, percebemos que todas possuem o mesmo prefixo, ou seja, todas iniciam com as letras “iP”:
- iPod
- iPad
- iPhone
Assim, podemos tornar nossa expressão mais eficiente deixando claro que o padrão começa com “iP”, e depois disso, há três alternativas:
iP(od|ad|hone)
Essa nova expressão continua casando as três palavras, mas agora ficou menor e mais rápida. Porém, agora ela ficou mais difícil para ler e entender. Trocamos legibilidade por eficiência.
Aplicando mais uma vez a mesma técnica de identificar padrões e melhorar a expressão, podemos perceber que tanto iPod quanto iPad terminam com a letra “d”. Podemos isolar esta letra, trocando o trecho od|ad
por [oa]d
:
iP([oa]d|hone)
Continuamos casando as mesmas palavras, porém agora a legibilidade foi pelo ralo. É preciso interpretar a expressão mentalmente para saber quais são as palavras que ela casa. Será que fomos longe demais?
Você sempre deve avaliar se esse tipo de melhoria é mesmo uma vantagem.
- Era necessário otimizar a expressão?
- A expressão anterior estava lenta?
- Todos que darão manutenção nesta expressão saberão entendê-la?
- O que é mais importante: velocidade ou legibilidade?
Acostume-se a sempre fazer estas perguntas a si mesm[ao] cada vez que for melhorar alguma expressão regular. Você pode se surpreender com as respostas :)
Às vezes, é possível encontrar um meio termo que não prejudica tanto a legibilidade, mas resulta em um ganho na performance.
i(Pod|Pad|Phone)
Nesta expressão, isolei somente a letra “i”, que é um prefixo muito conhecido para os produtos da Apple. Deixei o “P” repetindo em todas as alternativas para não quebrar as palavras. Assim fica clara a separação entre o prefixo “i” e o nome dos produtos: Pod, Pad e Phone.
i(Phone|Pod|Pad)
Como última melhoria, movi o trecho “Phone” para o início das possibilidades, para deixar mais claro que esta é uma lista de palavras com produtos da Apple. As alternativas Pod e Pad são muito parecidas e podem gerar confusão. Deixando o “Phone” no início, ali bem pertinho do “i”, fica mais fácil do leitor enxergar “iPhone” e deduzir o iPod e iPad com mais facilidade.
Agora, comparemos as duas expressões:
iP([oa]d|hone) i(Phone|Pod|Pad)
A primeira seguiu somente o caminho da eficiência, enquanto a segunda fez um balanço entre eficiência e legibilidade.
Nos meus primeiros anos de expressões regulares, eu faria sempre a primeira, pois é a menor e mais eficiente. Hoje, depois de já ter sofrido muito dando manutenção para minhas próprias expressões enigmáticas do passado, valorizo mais uma expressão legível, melhorando a velocidade somente quando estritamente necessário.
Quem já usa as Funções ZZ há tempos, sabe que seu código era afetado por essa mentalidade do “menor é melhor”. Ainda bem que evoluí :)
Aprenda mais sobre os tópicos deste texto: