Regex – Como definir 2 limites e pegar todo conteúdo dentro?

Regex – Como definir 2 limites e pegar todo conteúdo dentro?

24 de agosto de 2019 0 Por Ramos de Souza Janones
Como vender Software - Seja desktop, web ou MobilePowered by Rock Convert
Powered by Rock Convert

Dica sobre programação usando Regex – Como definir dois limites e pegar todo conteúdo dentro. Um exemplo prático passo a passo completo.

Considerando que o delimitador terminal só pode aparecer uma única vez, e que ele é de apenas um caractere no seu exemplo é o %), fiz um pequeno ajuste na resposta do nullptr para tal fim:

ENERGIA ELETRICA CONSUMO[^%]*%

Agora, em termos gerais:

Para qualquer sequência iniciadora INIT, podendo ela ser repetida na sequência, e um terminador @de um caracter que não pode estar contido exceto no final da sequência:

INIT[^@]*@

Para um iniciador qualquer de um caracter £ que não pode ser repetido dentro e um terminador de um caracter que também não pode ser repetido:

£[^£@]*@

Se for plausível aceitar um caracter de escape (fingindo ser o #), em que o escape pode se escapar também, e que o iniciador £ ou o terminador @ podem ser escapados no meio da sequência (não podendo aparecer livres):

£([^#£@]|#.)*@

Aqui, vale uma explicação:

  • começa com £, como esperado de um iniciador
  • termina com um @, como esperado de um terminador
  • pode conter um grupo com diversas repetições de g1 ou g2
  • g1 é qualquer caracter que não seja escape, iniciador ou terminador
  • g2 é o escape seguido de qualquer coisa, incluindo (mas não limitado a): iniciador, escape e terminador

Como consequência da montagem de g1, um escape só poderá aparecer em elemento de g2. E g2começa garantidamente com um escape e tem um outro caracter; logo, não há escapes faltando, eles estão sempre seguidos de algo.

SQL e Regex – Entenda quando e como usar em instruções SQL

Se por acaso a sequência que não pode se repetir no meio for de mais de 1 caracter, a coisa fica um pouco mais complicada e feia de se escrever.

Note que estou usando aqui apenas regex “pura”, possível de ser representada por um autômato de estados finito; logo, retrovisores estão fora do meu escopo de escrita abaixo

Tome, por exemplo, a sequência @€ como terminadora, e que eu preciso que ela não se repita. Assumindo que o iniciador £ pode se repetir, e também na ausência de escapes.

Um simples @ não significa que a sequência foi preenchida. Para tal, é necessário que o próximo caracter não seja . E também pode ocorrer o caso de que o @ seja a parte logo anterior ao terminador @€. Então eu preciso pegar, no miolo da regex:

  • um @ sucedido por qualquer coisa que não seja 
  • o próprio  desde que garantido que não haja algum casamento com algo que termine em @ no meio da repetição
  • possivelmente uma fração do terminador

Posso separar o miolo na parte de passível repetição e na parte de incompletude. Assim, a parte de incompletude, para um terminador de 2 caracteres apenas, é (@+)? (já já explico a cruz de Kleene). E a parte passível de repetição?

([^@]|@+[^€])*

Assim, eu posso ter uma sequência arbitrária dentro dessa repetição que, garantidamente, não vai terminar com @. A repetição é composta de 2 grupos: g1 que é qualquer coisa menos o primeiro caracter do terminador, e g2, que é o caracter iniciador seguido de necessariamente algo que quebre a sequência do terminador.

Então, para permitir também a parte inicial do terminador, permito que seu primeiro caracter se repita infinitamente, de modo opcional, após essa sequência, ficando assim toda a regex:

Powered by Rock Convert
£([^@]|@+[^€])*(@+)?@€

E se o terminador fosse de 3 caracteres? Como o @€¥?

Bem, a ideia é semelhante, mas vai precisar negar no primeiro caractere, no segundo caractere e no terceiro caractere a sequência. Como fazemos isso?

  • a negação do primeiro caracter é direta: [^@]
  • a negação do segundo caracter em diante deve assumir a presença do primeiro caracter, com possibilidade de repetição, então vou colocá-las todas em um grupo precedido de @*
  • a negação do segundo caracter (já considerando que foi tratada externamente a repetição do primeiro caracter), começa assumindo que seu casamento positivo para o primeiro caracter e negando o segundo caracter: @[^€]
  • a negação do terceiro caracter (também assumindo que já foi tratada a repetição do primeiro caracter) precisa assumir que deram certo os dois primeiros caracteres: @€[^¥]

Então, fica assim a parte passível de repetição:

([^@]|@*(@[^€]|@€[^¥]))*

Para a parte de sequência incompleta, só tirar as listas negadas e a estrela de Kleene final, substituindo-a pela possibilidade de presença. Vou denotar como '' a string de comprimento 0 apenas por uma questão de visualização, em seguida eliminando-a:

(''|@*(@''|@€''))?

Como não faz sentido algo concatenado da string vazia na regex desejada:

(''|@*(@|@€))?

Como não faz sentido a opção entre nada ou outra coisa, sempre recaindo sobre a outra coisa:

(@*(@|@€))?

Poderia seguir aqui apenas com isso, mas, se você prestar atenção, isso pode ser substituído por algo mais expressivo:

(@*(@(€)?)?)?

Onde cada parêntese após a repetição do primeiro caractere da sequência terminadora indica que é opcional aquela subsequência. Note, também, que só faria sentido dar casamento nesse grupo se e somente se tiver pelo menos uma parte da sequência, e que necessariamente deve ser o primeiro caractere. Portanto, isso poderia ser reescrito assim:

(@+(€)?)?

Tirando parênteses redundantes:

(@+€?)?

Note, porém, que esse mesmo algoritmo poderia ser usado para uma string arbitrária abcdefX:

(a+(b(c(d(ef?)?)?)?)?)? 

Essa expressão casa com qualquer subsequência do início de abcdefX

E como ficaria toda a expressão?

£([^@]|@*(@[^€]|@€[^¥]))*(@+€?)?@€¥

Dá para expandir essa lógica para mais caracteres, mas devo assumir que é bem trabalhoso e o tamanho aumenta exponencialmente. Também não levei em consequência a possibilidade de haver caracteres repetidos na sequência terminadora, isso pode eventualmente gerar um caso complexo que não foi devidamente tratado.

» Programação

Powered by Rock Convert
Siga os bons!
Últimos posts por Ramos de Souza Janones (exibir todos)
vote
Article Rating
LEIA TAMBÉM:  5 Sites para aprender programar jogando