17 de maio de 2021

Do bit Ao Byte

Embarcados, Linux e programação

Regex no MicroPython – Programe menos!

lambda no micropython | regex no MicroPython

Comecei usar expressões regulares em meados dos anos 2000. Na época, em shell script, que aprendi profundamente com o livro do Mestre Julio Cezar Neves – o melhor, em minha opinião. Recomendei a um amigo na época. O livro é tão impactante que ele optou por virar psicólogo. Posteriormente comecei usar expressões regulares em Python, então em Qt. Onde dá pra usar, prefiro. O código fica menor e mais fácil de lidar e já que tenho feito uma série de artigos com a Raspberry Pi Pico, não custa nada falar de regex no MicroPython, já que não o fiz quando usando esse firmware em ESP8266.

Vale salientar que, claro, há o mesmo recurso em outras linguagens além de Python e Shell Script. Utilizo também em Qt, mas em todas elas existem diferenças e você deverá estudar cada uma delas, conforme a linguagem que for programar. Mas depois de aprender a primeira, o resto é fácil.

O que é regex?

Regex – ou, “expressão regular”, é uma forma de definir um padrão de busca em uma string complexa. Uma string complexa seria algo fora de um formato padrão. Vamos começar com um exemplo para discorrer a respeito. A string de exemplo será “22 de abril de 1500“. Nela vamos procurar pelos grupos numéricos:

import re
msg = "22 de abril de 1500"
m = re.search('\d+')
m.group(0)

Primeiro importamos o módulo re, definimos uma mensagem (msg) e então criamos nosso padrão em m (que pode ser qualquer nome). Nesse caso específico, usamos search para procurar pelo padrão na string inteira. Usando group(0), pegamos a primeira ocorrência do padrão, que será “22“. Mas não seria mais fácil usar split e pegar o primeiro campo? – Claro que sim, se houver um padrão. Mas repare na expressão regular; \d+ significa “um dígito ou mais”. Não importa a posição que esteja, o padrão casará. Mas e se quiséssemos pegar o ano? Bem, considerando que o ano não seria o primeiro campo da string, podemos simplesmente adicionar um espaço à regex:

regex no MicroPython - search

Repare que agora a expressão que deve casar está protegida por parênteses. Isso significa que, apesar de explicitarmos o espaço, definimos que o que deve retornar está entre parênteses.

A expressão regular é uma forma de encontrar um padrão em uma variável sem padrões. O que aconteceria se mudássemos a string para “Sao Paulo, 22 de abril de 1500”? – Nesse caso, voltaria a casar 22, já que definimos um padrão numérico precedido por espaço. Se a intenção é casar o ano, devemos reformular a regex:

regex no MicroPython - casando ano

Mas que coisa, não? Anteriormente bastava usar ‘\d+’, agora foi necessário especificar 4 vezes o dígito (‘\d’). Por quê? – Bem, no caso do MicroPython há uma clara razão: Nem todos os recursos estão disponíveis por questões de recurso da MCU. Se fosse no laptop, bastaria usar o padrão re.search(‘\d{4}’).

regex no MicroPython - ausente

Com isso, nem foi necessário preceder a expressão com espaço, já que podemos precisar exatamente o que queremos. Assim, tenha em mente que expressão regular no MicroPython tem limitações. Mas se estivéssemos procurando por ano ou dia, já teríamos resolvido a questão, mesmo que a string varie:

Ao usarmos expressões regulares, não significa que estamos economizando processamento, mas com certeza reduzimos a quantidade de código que devemos escrever por nós mesmos ao casar padrões.

Funções da regex

Para exemplificar o uso, utilizei a função search. Temos outras funções bastante úteis, mas uma coisa que também precisa ser considerada é o tratamento dos resultados. Nem sempre o padrão pode casar, ainda mais considerando que estamos tratando uma string variável.

O group é apenas uma das funções de search. Seja lá qual for a função escolhida, use help(funcao) para ver o que mais ela oferece. Por exemplo, podemos saber o início e o fim de um padrão encontrado com search, usando start() e end() respectivamente – ou, podemos usar a função span, que retorna uma tupla com início e fim. Use o que melhor convier à sua lógica.

Além dessas, temos as funções compile, match, e sub no módulo regex no MicroPython. A referência dos recursos disponíveis na regex no MicroPython está disponível na documentação. Considerando as limitações do link anterior, todo o resto sobre expressões regulares pode ser visto na documentação do Python, no módulo regex. Esse último link está repleto de exemplos, muito mais do que o módulo oferece em MicroPython, infelizmente.

A intenção desse artigo era realmente apresentar a regex no MicroPython como recurso, que pode ajudar um bocado. No começo é fácil “apanhar” das expressões regulares porque tem um conjunto de regras que só lendo a documentação para aplicar adequadamente. Por exemplo, na string “<h2>Teste de tamanho</h2>”. Para pegar só o primeiro “h2” poderíamos nos equivocar escrevendo a regex como “re.search(‘<.*>’,msg)“. À primeira vista está correto; casar o sinal, o que estiver dentro dele e seu fechamento (‘<.*>‘). Porém o asterisco é chamado de “caractere guloso”. Ele vai “devorar” tudo o que estiver pela frente até o último casamento – que é a tag </h2>, porque o último caractere que casa com a expressão está aí. Para evitar que ele percorra a string inteira, usamos o limitador ‘?’, que se refere a 0 ou 1 ocorrência.

regex no MicroPython - erro comum

Em suma, regex precisa ser estudada, mas é trabalho de um dia, que lhe poupará esforço pelo resto de sua vida.