Você está na página 1de 68

Expressões Regulares com Delphi

Esta é a sua cópia pessoal da apostila

Olá Jailson Santos! É com grande satisfação que lhe disponibilizamos


esta apostila sobre o tema “Expressões Regulares com Delphi”.

Por conta de um compromisso em poupar recursos e contribuir por um


mundo melhor não imprimiremos o material e acreditamos que em geral não
há necessidade de se fazer isto. Por isto esta é uma cópia pessoal do material.

Esperamos que você compartilhe este material com seus colegas, mas
pedimos a gentileza de não compartilhar na grande web. Futuras atualizações
serão enviadas diretamente ao seu e-mail, jailson.santos@g4solutions.com.br e
por isso solicitamos que mantenha seu cadastro atualizado.

Uma informação relevante é que este material é uma compilação dos


artigos do autor Mário Guedes para a Active Delphi bem como postagens no
blog eugostododelphi.blogspot.com o que implica que eventualmente algum
texto lhe pareça familiar. Outras fontes serão devidamente creditadas ao fim
da apostila.

O seu canal de comunicação conosco é através do e-mail


aluno@arrayof.com.br.

Sugestões de melhoria serão sempre bem vindas!

Muito obrigado pelo prestígio de sua companhia.

Sobre esta apostila

Versão: 001 - Abril/2014


Revisor: José Mário Silva Guedes
Dono: Jailson Santos

Sobre a arrayOF

A arrayOF Consultoria e Treinamento tem por filosofia desenvolver o


potencial de seus parceiros ensinando e aprendendo com eles.

Cópia pessoal de:


1 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Sumário
Esta é a sua cópia pessoal da apostila ...................................................................... 1
Sobre esta apostila ........................................................................................................ 1
Sobre a arrayOF ............................................................................................................. 1
Material de apoio .......................................................................................................... 5
Introdução ...................................................................................................................... 5
Propósito da Expressão Regular................................................................................... 6
Princípios básicos ........................................................................................................ 6
Motor RegEx ................................................................................................................ 7
Utilização no Delphi ................................................................................................... 7
Dominando os meta-caracteres ................................................................................. 9
Ponto: . ....................................................................................................................... 10
Escape: \ ................................................................................................................... 11
Circunflexo: ^ ............................................................................................................ 12
Cifrão: $...................................................................................................................... 13
Pipe: | ........................................................................................................................ 14
Colchetes: [ ] ............................................................................................................. 15
Quantificadores ........................................................................................................ 16
Estrela: * .................................................................................................................. 16
Cruz: + ..................................................................................................................... 18
Interrogação: ? ..................................................................................................... 19
Chaves: {n,n } ........................................................................................................ 20
Ganância versus Preguiça .................................................................................. 21
Quantificador possesivo ...................................................................................... 22
Parênteses: ( ) ........................................................................................................... 24
Agrupamento com alternância: ........................................................................ 24
Agrupamento com quantificador: .................................................................... 25
Referência Anterior: ............................................................................................. 26
Utilização na linguagem hospedeira ................................................................ 27
Modificador de grupo: ............................................................................................ 29
Grupo de não captura: (?: subexpressão) ....................................................... 29
Grupo de comentário: (?# comentário) ......................................................... 30
Grupo nomeado: (?<nome> subexpressão) .................................................... 30

Cópia pessoal de:


2 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Grupo modificador de modo: (?i) e (?-i) .......................................................... 31


Modificador de RegEx................................................................................................. 33
Aplicativo de estudo ............................................................................................... 33
Os modificadores ..................................................................................................... 36
Nenhuma opção marcada: roNone ................................................................. 36
Ativar combinação insensível à caixa tipográfica: roIgnoreCase .............. 36
Ativar modo de captura explícita: roExplicitCapture ..................................... 37
Habilitar comentários de linha: roIgnorePatternSpace .................................. 38
Compilar a RegEx: roCompiled .......................................................................... 39
Tratamento de múltiplas linhas: roMultiLine ...................................................... 41
Tratamento de linha simples: roSingleLine ........................................................ 42
Tipos para Manipulação de ReGex no Delphi ........................................................ 44
Tipo: TRegEx ............................................................................................................... 45
Método: TRegEx.IsMatch ..................................................................................... 46
Método: TRegEx.Escape ...................................................................................... 46
Método: TRegEx.Match ....................................................................................... 47
Método: TRegEx.Matches.................................................................................... 47
Método: TRegEx.Replace .................................................................................... 47
Método: TRegEx.Split ............................................................................................ 50
Tipo: TMatch .............................................................................................................. 51
Método: TMatch.NextMatch .............................................................................. 51
Método: TMatch.Result ........................................................................................ 53
Tipo: TMatchCollection ............................................................................................ 54
Tipo: TGroup .............................................................................................................. 55
Tipo: TGroupCollection ............................................................................................ 55
Abordagens Avançadas com RegEx ....................................................................... 56
Grupo de condição: (?(<Retro referência>)<ER verdadeiro>|<ER falso>) .... 56
Grupo olhar em volta (look around) ..................................................................... 57
Abreviações de caracteres .................................................................................... 61
Abreviações de classes de caracteres ................................................................ 61
Problemática de acentuação e outras línguas .................................................. 62
Classes de caracteres POSIX .............................................................................. 64
Trabalhando com Unicode ................................................................................. 65

Cópia pessoal de:


3 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Escape octal - \<número........................................................................................ 67


Âncoras e outras asserções de largura zero ........................................................ 68

Cópia pessoal de:


4 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Material de apoio

Todos os códigos dos exemplos citados nesta apostila estão disponíveis


no GitHub:

https://github.com/arrayOF/expressoes_regulares_com_delphi.git

Introdução

Expressão Regular, que daqui para frente chamaremos apenas de


RegEx, é uma das ferramentas mais úteis que um programador pode contar. A
incorporação desta ferramenta a partir do Delphi XE nos oferece um salto de
qualidade nos projetos que não nos permite ignorá-la.

Não parece um assunto fácil. Mas é! O objetivo desta série de artigos é


o de desmistificar este assunto, em especial para nós programadores Delphi
que não tínhamos esta ferramenta tão à mão como temos hoje.

E perceba que você levará este aprendizado, tal qual como você verá
aqui, para outras linguagens com as quais eventualmente você vier a
trabalhar, como Python ou JavaScript.

Antes, devemos ter em mente que o Delphi XE passou a incorporar uma


biblioteca de código aberto denominada PCRE – Perl Compatible Regular
Expressions (http://www.pcre.org/).

As units System.RegularExpressions, System.RegularExpressionsCore e


System.RegularExpressionsAPI encapsulam os OBJs (desenvolvidos em C++) e
por isso não necessitamos distribuir nenhuma DLL junto com o executável. Essa
informação é importante, pois caso você encontre diferenças de uso em
outras linguagens é por que essa outra linguagem provavelmente não seja
baseada na PCRE.

Outra informação importante se diz respeito aos usuários que utilizam


Delphi anteriores à versão XE. Para estes existe uma opção em
http://www.regular-expressions.info/delphi.html sendo que a usei por muito
tempo e não há nada que a desabone.

Cópia pessoal de:


5 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Propósito da Expressão Regular

O objetivo primário da RegEx é a manipulação de texto. Mas de uma


forma tal que não há limites nem soluções impossíveis. E o melhor: De
implementação rápida e inequívoca.

Em geral a primeira dúvida que surge em relação à RegEx é quanto sua


real utilidade. Afinal, sobrevivemos sem ela até hoje. Por que complicar? Mas
na verdade o que acontece é que perdemos muito tempo com as outras
soluções de manipulação de texto. E sempre fica um furo. Sempre.

Então, a RegEx pode ser usada para:

 Validação de entrada;
o e-Mail;
o Endereço IP;
o URL;
o Data;
o Telefone;
o CPF;
 Análise de LOG;
 Consistência de arquivo XML;
 Busca e substituição de texto;
 E qualquer outra solução que envolva texto.

Princípios básicos

Primeiramente, vamos conhecer os princípios básicos. Temos que


considerar três elementos ao se trabalhar com RegEx:

 O padrão a ser buscado: É a RegEx propriamente dita, que não passa


de uma string com alguns símbolos especiais;
 O texto a ser analisado: Basicamente uma string, com ou sem quebra
de linhas;
 Os modificadores a serem aplicados: São sinalizações que afetam o
comportamento da máquina RegEx;

O objetivo ao se aplicar uma RegEx a um texto é justamente o de se


recuperar as combinações. Podemos ter nenhuma, uma, ou várias
combinações. Cada combinação por sua vez pode ter vários grupos. Se isso
não estiver fazendo sentido para você, calma: fará mais para frente.

Já no tocante à construção da RegEx, observe que ela é constituída


por pequenos blocos de montagens, que se dividem em duas categorias:

Cópia pessoal de:


6 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

 Meta-caractere: São caracteres com funções especiais dentro


da RegEx;
 Caractere literal: Não tem função especial dentro da RegEx,
sendo interpretado literalmente.

Cada parte de uma RegEx, em geral, é referenciado por átomo.

No exemplo acima temos quatro caracteres. Deles, só o circunflexo é


um meta-caractere enquanto que os outros são caracteres literais. E,
independentemente disso, cada caractere é um átomo da RegEx.

Motor RegEx

Existe um elemento envolvido na RegEx que é conhecido como motor


RegEx. Basicamente é o algoritmo que resolve a Expressão Regular em um
determinado alvo. Obviamente não há espaço para detalhar o
funcionamento do motor RegEx mas é importante termos consciência da
necessidade de estudarmos em algum momento suas peculiaridades para
podermos fazer uma RegEx mais assertiva.

Dentro do motor RegEx existe um conceito muito importante que é o


backtracking. A grosso-modo, este conceito faz com que o motor RegEx
considere cada sub expressão ou átomo de cada vez e sempre que precisar
decidir entre duas alternativas viáveis ele opta por uma e memoriza a outra
para voltar a ela mais tarde, se for necessário.

Utilização no Delphi

Todos os recursos necessários para se trabalhar com RegEx está na unit


RegularExpressions.

A fim de testarmos gradualmente as expressões regulares no Delphi,


vamos desenvolver o seguinte aplicativo:

Cópia pessoal de:


7 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

eRegEx:
TEdit

fRegEx:
mTexto:
TForm
TMemo
tvResultado:
clbModificador: TTreeView
TCheckListBox

bProcessar: TButton

Segue abaixo o código do botão bProcessar.

O objetivo será o de aplicar a RegEx descrita no Edit eRegEx no texto


descrito no Memo mTexto e colocar os resultados obtidos na TreeView
tvResultado.

A CheckListBox clbModificador será usado mais para frente, em um


futuro artigo desta série.

Este projeto será incrementado ao longo dos artigos e o sua opinião


será muito bem vinda.

procedure TfRegEx.bProcessarClick(Sender: TObject);


var
_RegEx : TRegEx; //Record responsável por aplicar a expressão regular
_Matches : TMatchCollection; //Coleção de combinações
_Matche : TMatch; //Uma combinação
oNode : TTreeNode; //Nó da treeview com as informações de uma combinação
begin
tvResultado.Items.Clear;
_Matches := _RegEx.Matches(mTexto.Text,eRegEx.Text);
if (_Matches.Count > 0) then
begin
for _Matche in _Matches do
begin
oNode := tvResultado.Items.Add(nil,_Matche.Value);
tvResultado.Items.AddChild(oNode,Format('Index: %d',[_Matche.Index]));
tvResultado.Items.AddChild(oNode,Format('Length: %d',[_Matche.Length]));
end;
end;
end;

No decorrer desta apostila esse vai ser o máximo de código que você
irá digitar. É isto mesmo! Voltaremos neste exato trecho para incrementar uma
coisa aqui e outra ali. Mas perceba que você conseguirá criar vários cenários
sem programar em Pascal.

Cópia pessoal de:


8 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Dominando os meta-caracteres

O domínio do assunto passa pelo pleno entendimento dos meta-


caracteres. Vamos conhecer a partir de agora a função de cada um deles.
Mas perceba que isto é só o começo. A combinação entre eles multiplica as
possibilidades.

A figura abaixo mostra todos, isso mesmo, todos os meta-caracteres que


compões uma RegEx. São apenas 15 elementos.

Os meta-caracteres podem ser agrupados em quatro categorias:

 Representante: Representa algum caractere, como o ponto que


combina com qualquer caractere naquela posição.
 Quantificador: Determina a quantidade de ocorrências de um átomo
da RegEx como o asterisco, que indica que nenhuma, uma ou mais
ocorrências são permitidas do átomo predecessor.
 Âncora: Combina com uma posição no texto, a exemplo do cifrão, que
combina com o fim de uma string (e não com o último caractere).
 Outros: Funcionalidades diversas.

Vamos aos nossos primeiros meta-caracteres.

Cópia pessoal de:


9 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Ponto: .

O meta-caractere ponto combina com qualquer caractere. Ele


representa uma classe de caracteres, assunto que veremos mais para frente.

Perceba que o ponto combinou com todos os caracteres da frase,


inclusive os espaços, gerando 18 combinações.

Cópia pessoal de:


10 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Escape: \

A função do escape, ou barra invertida, é o de anular um meta-


caractere, tornando-o literal. O ponto, como vimos anteriormente, combina
com qualquer caractere. Mas e se quisermos combinar uma posição,
inequivocamente, com um ponto? Simplesmente escapa-se o ponto na
expressão regular.

Vale ressaltar que o escape, quando combinado com um não meta-


caractere, como o A maiúsculo, por exemplo, pode gerar uma meta-string,
oferecendo uma funcionalidade avançada. Conheceremos algumas meta-
strings em outro artigo.

Cópia pessoal de:


11 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Circunflexo: ^

O circunflexo é do tipo âncora, ou seja, ele não combina com um


caractere específico, mas sim com o início de linha.

Observe no exemplo acima que temos três ocorrências da letra A, mas


conseguimos combinar somente com a do início da linha usando o circunflexo
no início da RegEx.

Cópia pessoal de:


12 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Cifrão: $

A primeira coisa a considerar sobre este meta-caractere é que o nome


dele é cifrão e não dólar como muitos se referem. Ele também é do tipo
âncora e combina com o fim da linha.

Neste exemplo conseguimos capturar a última letra C, pois indicamos


que queremos uma letra C seguida pelo final da linha.

Cópia pessoal de:


13 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Pipe: |

O pipe nos oferece alternância. O que nos dá bastante versatilidade no


momento de se montar a RegEx.

Perceba no exemplo acima que obtivemos dois resultados com a


mesma RegEx: ou rato, ou roupa.

Cópia pessoal de:


14 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Colchetes: [ ]

Os colchetes representam uma classe de caracteres. Determina um


conjunto finito de possibilidades de combinação para aquela posição na
RegEx. Olhando de longe, parece com o pipe que vimos na seção anterior,
mas não tem nada a ver.

Perceba que criamos uma classe de caracteres com intervalo, pois


usamos o traço entre o 6 e o 9 dentro dos colchetes equivalendo a [6789].
Também poderíamos negar esta classe e para isso bastaria usar o circunflexo
no início da lista. Perceba na figura a seguir que conseguimos mudar
totalmente o resultado com a adição do circunflexo.

Cópia pessoal de:


15 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Quantificadores

Os meta-caracteres quantificadores determinam a quantidade de


ocorrências do átomo anterior ao símbolo.

Existem três tipos de quantificadores: gananciosos, preguiçosos e


possesivos. Veremos mais sobre este detalhe mais para frente. No momento, o
que nos basta conhecer são os meta-caracteres quantificadores: * + ? { }

Estrela: *

A estrela é comumente chamada de asterisco, porém o significado de


asterisco é o de marcar notas sobre passagens de texto. Obviamente que é
um mero detalhe de semântica, mas acredito ser uma definição importante.

A estrela indica que pode haver uma, várias ou nenhuma ocorrência do


átomo imediatamente anterior.

No exemplo acima, estamos procurando uma sequência de caracteres


de zero a nove. Este exemplo é ótimo, pois nos leva a um detalhe muito
importante: A estrela está se referindo ao átomo [0-9] e não apenas ao
colchete de fechamento da classe de caracteres, cujo assunto nós
abordamos na primeira parte.

Outro ponto sobre a definição da estrela é sobre a possibilidade de não


haver nenhuma ocorrência do átomo anterior. Isso significa que a RegEx não
irá falhar na ausência do átomo anterior, como no exemplo abaixo:

Cópia pessoal de:


16 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Cópia pessoal de:


17 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Cruz: +

Normalmente nos referimos a este símbolo como adição ou


simplesmente “mais”. Mas o fato que o nome do símbolo é cruz. A cruz indica
que deve haver uma ou mais ocorrências do átomo anterior. Se a condição
não for satisfeita, toda a RegEx falha.

No exemplo acima, tivemos o mesmo resultado da estrela. Mas no


exemplo abaixo, percebemos que a RegEx falha.

Cópia pessoal de:


18 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Interrogação: ?

O meta-caractere interrogação exige apenas uma ou nenhuma


ocorrência do átomo anterior. Perceba no exemplo abaixo que apenas o
último zero entrou no resultado.

Vamos tirar os caracteres que formam a palavra “reais” para


observamos que ao invés de um único resultado (1000), obtemos quatro
resultados distintos:

Cópia pessoal de:


19 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Chaves: {n,n }

As chaves criam um quantificador de intervalo, ou seja, indica um valor


mínimo é máximo de ocorrências do átomo anterior. É importante notar que o
preenchimento dos valores de intervalo tem toda a relevância.

No exemplo abaixo, estamos especificando que queremos de uma a


quatro ocorrências do átomo [0-9].

Mas poderíamos indicar um valor exato de ocorrências: {4} ou somente


o valor mínimo de ocorrências: {1,}

Cópia pessoal de:


20 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Ganância versus Preguiça

Os quantificadores, tais quais foram mostrados até aqui, se classificam


como quantificadores gananciosos. Ganancioso (ou guloso) se refere ao fato
do quantificador tentar casar com o máximo possível, cedendo caractere
conforme a necessidade do próximo átomo.

No exemplo abaixo, temos uma linha CSV, necessidade muito comum


no dia a dia. O objetivo óbvio de uma RegEx mínima é o de recuperar os
campos individualmente. Mas veja o resultado da primeira tentativa:

Mas por que o motor RegEx não parou no primeiro ponto e vírgula no
texto, recuperando “Campo 1;”? Por que pelo fato da estrela ser gananciosa
ele percebeu o primeiro ponto e vírgula e guardou sua posição para voltar
atrás caso ele não encontrasse nenhum outro pela frente ou se o átomo
posterior exigisse isso.

Para resolver este problema lançamos mão, então, dos quantificadores


preguiçosos. Um quantificador preguiçoso sempre tenta parar a combinação,
somente combinando se o átomo seguinte falhar. Para tornar o quantificador
preguiçoso basta colocar uma interrogação após o átomo:

Ganancioso Preguiçoso
* *?
+ +?
? ??
{n,n} {n,n}?

Cópia pessoal de:


21 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Por fim, eis a solução para o problema inicial:

Soluções envolvendo tags por exemplo (XML, HTML) passarão pela


decisão de se usar um quantificador ganancioso ou preguiçoso.

Quantificador possesivo

Existe ainda os quantificadores possesivos e são usados para otimização


de RegEx. Usando o quantificador possesivo indicamos ao motor RegEx que
ela pode falhar imediatamente se o átomo não for satisfeito.

Para tornar um quantificador possesivo basta adicionar a cruz após o


quantificador. Veja nossa tabela expandida.

Ganancioso Preguiçoso Possesivo


* *? *+
+ +? ++
? ?? ?+
{n,n} {n,n}? {n,n}+

Obviamente deve ser usado com muito cuidado, pois podemos


facilmente fazer com que nossa RegEx não obtenha o resultado desejado.
Veja no exemplo abaixo uma situação de falha.

Cópia pessoal de:


22 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Mas porque a RegEx falha? Porque o .* casou até o último caractere.


Mas logo depois queremos um ponto é vírgula, mas como usamos um
quantificador possesivo o motor RegEx não volta atrás e portanto falha. O fato
de o último caractere ser justamente um ponto e vírgula é meramente uma
coincidência.

Cópia pessoal de:


23 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Parênteses: ( )

Os parênteses são utilizados para agrupar e capturar e logo


entenderemos do que se tratam esses termos. A utilização básica é
exemplificada abaixo:

Figura 1: Exemplo básico de utilização de agrupadores

A princípio nenhuma novidade. Conseguiríamos o mesmo resultado


sem o uso dos parênteses, ao menos neste cenário. Vamos, então, conhecer
os usos possíveis.

Agrupamento com alternância:

O agrupamento pode ser usado para limitar o escopo de uma


alternância. Como sabemos, a alternância é oferecido pelo caractere pipe.
Digamos que em um texto qualquer queremos retornar tanto “Delphi XE2”
quanto “Delphi 7”.

A primeira alternativa talvez fosse Delphi XE2|Delphi 7 e isso


funcionaria. Mas seria inaceitável em um RegEx maior e com muitas opções de
alternância. Então devemos limitar o escopo da alternância com o
agrupamento:

Figura 2: Exemplo de agrupamento com alternância


Cópia pessoal de:
24 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Esse recurso também melhora o desempenho da RegEx. Mas deve-se


também tomar cuidado com a ordem das alternativas, pois a primeira a
combinar é a que vale mesmo que haja alguma alternativa mais exata
depois. Compare os resultados abaixo onde vou incluir o Delphi XE na busca:

Figura 3: Exemplo de agrupamento com alternância com falha

No exemplo acima o Delphi XE2 não aparece na lista de resultados, pois


ao analisar a última linha do texto a RegEx retornou com sucesso ao satisfazer
à segunda opção do grupo, no caso XE. Invertendo as opções dentro do
grupo temos o resultado esperado:

Figura 4: Exemplo de agrupamento com alternância corrigido

Apesar disto, certamente a melhor RegEx para este cenário seria:


Delphi (7|XE2?) onde o 2 seria opcional.

Agrupamento com quantificador:

O agrupamento também é útil para podermos quantificar as


ocorrências do texto combinado. Vale as mesmas regras descritas no artigo
anterior sobre quantificadores gananciosos, preguiçosos e possesivos. No

Cópia pessoal de:


25 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

exemplo abaixo vamos listar todos os endereços IP de uma determinada


listagem:

Figura 5: Exemplo de agrupamento com quantificador

Perceba que o quantificador {4} (exatamente quatro ocorrências) foi


aplicado ao grupo predecessor e não a um átomo específico. Este grupo, por
sua vez, retorna um conjunto de um a três caracteres numéricos precedidos ou
não por ponto.

Referência Anterior:

Um uso prático do agrupamento é na própria RegEx, onde temos um


elemento chamado referência anterior, também conhecido como retrovisor.
Como o nome sugere este elemento “olha para trás”. Então, a função de
captura é justamente essa: oferecer para a RegEx o valor combinado pelo
parênteses para uso futuro.

O retrovisor é representado pelas meta-strings de \1 até o \9 . Temos,


portanto, apenas nove possibilidades de reuso na mesma RegEx. Um bom
exemplo de uso é em um formato XML, como no exemplo abaixo:

Figura 6: Exemplo de agrupamento com referência anterior

Perceba que mesmo sem especificar o nome das tags de abertura e


fechamento conseguimos recuperar os elementos individualmente.

Vamos analisar a RegEx:

<([a-z]*)>.*</\1>

Cópia pessoal de:


26 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Interpretação Átomo Resultado


 Sinal de menor, seguido por: < <
 Início de grupo (
 Qualquer caractere de ‘a’ à [a-z]* nome
‘z’ em qualquer quantidade
 Fim de grupo, seguido por: )
 Sinal de maior, seguido por: > >
 Qualquer caractere em qualquer .* Júlio
quantidade, seguido por:
 Sinal de menor, seguido por: < <
 Barra normal, seguido por: / /
 Valor do grupo 1, seguido por: \1 nome
 Sinal de maior > >
Tabela 1: Análise de expressão regular

Importante salientar que o retrovisor faz referência ao resultado obtido


pelo grupo e não à subexpressão contida nela.

Vale a pena ainda ressaltar que a contagem dos grupos se dá na


mesma ordem das aberturas dos parênteses da esquerda para a direita,
mesmo que estejam aninhados.

Utilização na linguagem hospedeira

No Delphi, assim como em outras linguagens que oferecem RegEx,


podemos tirar proveito do grupo. No exemplo anterior nós conseguimos isolar o
elemento XML: <nome>Júlio</nome>

Mas provavelmente estamos mais interessados em recuperar o


conteúdo do elemento e não no elemento como um todo. Isto é possível com
o tipo TGroup. Cada combinação, ou cada TMatch, pode ter um ou mais
grupos. Vamos, então, modificar o código do botão bProcessar conforme a
listagem abaixo:

procedure TfRegEx.bProcessarClick(Sender: TObject);


var
_RegEx : TRegEx; //Record responsável por aplicar a expressão
regular
_Matches : TMatchCollection; //Coleção de combinações
_Matche : TMatch; //Uma combinação
oNode : TTreeNode; //Nó da treeview com as informações de uma
combinação
oNodeGrupo : TTreeNode; //Nó da treeview criando o nó de grupos
oNodeItemGrupo : TTreeNode; //Nó do treeviwe criando um grupo
_Group : TGroup; //Um grupo
begin
tvResultado.Items.Clear;
_Matches := _RegEx.Matches(mTexto.Text,eRegEx.Text);
if (_Matches.Count > 0) then
begin

Cópia pessoal de:


27 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

for _Matche in _Matches do


begin
oNode := tvResultado.Items.Add(nil,_Matche.Value);
tvResultado.Items.AddChild(oNode,Format('Index:
%d',[_Matche.Index]));
tvResultado.Items.AddChild(oNode,Format('Length:
%d',[_Matche.Length]));

{$REGION 'Analisando os grupos'}


if (_Matche.Groups.Count > 0) then
begin
oNodeGrupo :=
tvResultado.Items.AddChild(oNode,'Agrupamentos');
for _Group in _Matche.Groups do
begin
oNodeItemGrupo:=
tvResultado.Items.AddChild(oNodeGrupo,_Group.Value);
tvResultado.Items.AddChild(oNodeItemGrupo,Format('Index:
%d',[_Group.Index]));
tvResultado.Items.AddChild(oNodeItemGrupo,Format('Length:
%d',[_Group.Length]));
end;
end;
{$ENDREGION}

end;
end;
end;

Listagem 1: Novo código do botão bProcessar

No exemplo a seguir o objetivo será o de retornar apenas o conteúdo


do elemento XML nome:

Figura 7: Exemplo de grupo com captura

Perceba, porém, que retornou dois grupos: um com todo o elemento


XML e outro somente com o conteúdo. Isso acontece porque
independentemente de usarmos ou não um agrupamento na RegEx sempre
nos é oferecido o grupo 0 (zero) que contêm toda a combinação retornada.
Depois, se houver, retorna-se os agrupamentos definidos na RegEx.
Apesar de na RegEx podemos ter apenas nove referências anteriores,
isso não se aplica no Delphi, sendo que ele retorna tantos grupos quanto
houverem, como no exemplo abaixo:

Cópia pessoal de:


28 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 8: Exemplo de grupos com captura

Observe ainda que no código do botão bProcessar fizemos um loop


com for..in..do listando todos os grupos retornados. Caso seja necessário
capturar um grupo especifico pelo índice basta usá-lo em TGroupCollection
:

procedure TfRegEx.GrupoEspecifico;
var
_RegEx : TRegEx;
begin

ShowMessage(_RegEx.Match(mTexto.Text,eRegEx.Text,[]).Groups[11].Value)
;
end;

Listagem 2: Exemplo de retorno do valor de um grupo pelo índice numérico

No exemplo acima estamos retornando para o ShowMessage a 11ª


captura retornada na combinação .

Modificador de grupo:

Não bastasse o que vimos até aqui, existe um elemento chamado


“Modificador de Grupo”. Ele é representado pela interrogação logo após a
abertura do grupo. Em seguida deve vir o modificador propriamente dito.
Vamos conhecer alguns:

Grupo de não captura: (?: subexpressão)

Dependendo do tamanho da sua RegEx ou até mesmo do seu texto


alvo, e não sendo necessário a referência anterior, podemos poupar o motor
da RegEx desta tarefa. Isto tem influência no desempenho da RegEx como um

Cópia pessoal de:


29 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

todo. Se o grupo for simplesmente para limitar o escopo da alternância ou


para determinar o quantificador, vale a pena abrir mão da captura.

Figura 9: Exemplo de grupo de não captura

Perceba no exemplo acima que não temos o grupo 1, temos somente o


grupo 0 que na verdade reflete o mesmo resultado da combinação. Portanto
não podemos nem usar o \1 na RegEx nem retornar o Groups[1] no Delphi.

Grupo de comentário: (?# comentário)

Dependendo da complexidade da RegEx talvez valha a pena


comentar alguns trechos. Pois bem, isso também é possível:

Figura 10: Exemplo de grupo de comentário

Obviamente que o comentário não influenciou no resultado.

Grupo nomeado: (?<nome> subexpressão)

A fim de contribuir para a legibilidade da RegEx bem como contornar o


limite de 9 referências anteriores podemos nomear um grupo e fazer referência
a este grupo tanto na RegEx quanto no Delphi:

Figura 11: Exemplo de grupo nomeado


Cópia pessoal de:
30 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

No exemplo acima estamos nomeando o grupo para DDD. Para


recuperar no Delphi este grupo, usaremos um código parecido com o que
segue:

procedure TfRegEx.GrupoEspecifico;
var
_RegEx : TRegEx;
begin
ShowMessage(_RegEx.Match(mTexto.Text,eRegEx.Text,[]).Groups['DDD'].
Value);
end;
Listagem 3: Exemplo de retorno do valor de um grupo pelo índice nomeado

Ou seja, é a mesma construção da listagem 2, mas ao invés de nos


referir ao índice numérico, estamos nos referindo ao índice nomeado.

E para fazer uma referência anterior na RegEx usamos a meta strings


\k<nome> , como no exemplo abaixo, onde queremos apenas nomes
repetidos:

Figura 12: Exemplo de referência anterior a um grupo nomeado

Mais uma vez, estamos fazendo referência ao índice nomeado ao invés


do índice numérico, porém na própria RegEx.

Grupo modificador de modo: (?i) e (?-i)

A princípio a RegEx é case-sensitive. Digo a princípio, pois é uma


característica que podemos alterar. E uma forma de alterar é na própria
RegEx:

Figura 13: Exemplo de grupo modificador de modo


Cópia pessoal de:
31 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

No exemplo acima estamos procurando a palavra Delphi


independentemente do modo em que esteja – maiúscula ou minúscula.
Portanto o (?i) ativa o case-insensitive ao passo que o (?-i) desativa.

Cópia pessoal de:


32 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Modificador de RegEx

Os modificadores são muito importantes, pois modificam, ou seja,


influem no comportamento da máquina RegEx.

Aplicativo de estudo

Para estudarmos este elemento, vamos modificar o nosso programa de


exemplo que foi desenvolvido no primeiro artigo. Perceba que o TEdit que
colocamos para a escrever a RegEx será trocado por um TMemo, passando a
se chamar mRegEx. Essa é uma mudança importante e o motivo dela será
explicado mais para frente. Por ora, tome cuidado ao digitar a sua RegEx
certificando-se que ela possui apenas uma linha.

Então, proponha-se um novo layout:

mRegEx:
TMemo tvResultad
o:
TTreeView
mTexto:
TMemo

bProcessar: clbModificad
TButton or:
TCheckListBox

Figura 1: Lay-out do aplicativo de teste

Segue o print da janela Structure do Delphi dando uma ideia do


aninhamento dos elementos de tela.

Cópia pessoal de:


33 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 2: Estrutura dos elementos de tela

Vamos aos códigos.

A primeira coisa que precisamos saber é que os modificadores são


representados pelo tipo enumerado TRegExOption e ao fazer as combinações
devemos passar um conjunto de modificadores usando o tipo TRegExOptions.
Então, para usarmos cada um deles em nosso projeto, vamos listar as opções
no CheckListBox clbModificador. Segue o código do OnCreate do formulário:

procedure TfRegEx.FormCreate(Sender: TObject);


var
eModificador : RegularExpressions.TRegExOption;
sModificador : string;
begin
//Varremos toda a coleção de modificadores
for eModificador := Low(TRegExOption) to High(TRegExOption) do
begin
//Transformamos o tipo enumerado para string
sModificador := TypInfo.GetEnumName(TypeInfo(TRegExOption),Ord(eModificador));
//Adicionamos a opção ao CheckListBox
Self.clbModificador.AddItem(sModificador,nil);
end;
end;
Listagem 1: Evento OnCreate do formulário

Na listagem 2, vemos o código do botão bProcessar. Não houve


nenhuma modificação no que se refere ao uso da RegEx. Só estamos
colocando uma informação adicional, que é o tempo de processamento
para fazermos algumas considerações sobre desempenho.

Cópia pessoal de:


34 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

procedure TfRegEx.bProcessarClick(Sender: TObject);


var
_Matches : RegularExpressions.TMatchCollection; //Coleção de combinações
_Matche : RegularExpressions.TMatch; //Uma combinação
_Group : RegularExpressions.TGroup; //Um grupo

oNode : TTreeNode; //Nó da treeview com as informações de uma combinação


oNodeGrupo : TTreeNode; //Nó da treeview criando o nó de grupos
oNodeItemGrupo : TTreeNode; //Nó do treeviwe criando um grupo

_cronus : Diagnostics.TStopwatch; //Cronômetro para medição do tempo


begin
Screen.Cursor := crHourGlass;
try
tvResultado.Items.Clear;

{$REGION 'Fazendo a pesquisa'}


_cronus := TStopwatch.StartNew;
_Matches := TRegEx.Matches(mTexto.Text,mRegEx.Text,Self.ObterModificadores);
_cronus.Stop;
{$ENDREGION}

{$REGION 'Registrando o tempo de processamento'}


if (_cronus.ElapsedMilliseconds = 0) then
begin
StatusBar1.Panels[1].Text := Format('Tempo de processamento: [%d]
Ticks',[_cronus.ElapsedTicks]);
end else
begin
StatusBar1.Panels[1].Text := Format('Tempo de processamento: [%d] Milisegundos - %d
Ticks',[_cronus.ElapsedMilliseconds,_cronus.ElapsedTicks]);
end;
{$ENDREGION}

{$REGION 'Analisando as combinações'}


if (_Matches.Count > 0) then
begin
for _Matche in _Matches do
begin
oNode := tvResultado.Items.Add(nil,_Matche.Value);
tvResultado.Items.AddChild(oNode,Format('Index: %d',[_Matche.Index]));
tvResultado.Items.AddChild(oNode,Format('Length: %d',[_Matche.Length]));

{$REGION 'Analisando os grupos'}


if (_Matche.Groups.Count > 0) then
begin
oNodeGrupo := tvResultado.Items.AddChild(oNode,'Agrupamentos');
for _Group in _Matche.Groups do
begin
oNodeItemGrupo:= tvResultado.Items.AddChild(oNodeGrupo,_Group.Value);
tvResultado.Items.AddChild(oNodeItemGrupo,Format('Index: %d',[_Group.Index]));
tvResultado.Items.AddChild(oNodeItemGrupo,Format('Length: %d',[_Group.Length]));
end;
end;
{$ENDREGION}

end;
end;
{$ENDREGION}

finally
Screen.Cursor := crDefault;
end;
end;
Listagem 2: Evento OnClick do botão bProcessar

Perceba que no momento de processar a RegEx, o terceiro parâmetro


está chamando o método ObterModificadores do formulário. Como dito

Cópia pessoal de:


35 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

anteriormente, este parâmetro requer um conjunto de opções o que


normalmente seria passado com colchetes. Para o nosso aplicativo ficar
funcional, vamos usar as opções selecionadas no CheckListBox. O código
deste método está na listagem 3:

function TfRegEx.ObterModificadores: TRegExOptions;


var
sModificador : string;
eModificador : RegularExpressions.TRegExOption;
i : Integer;
begin
//Iniciamos o Result como um conjunto vazio
Result := [];
//Varremos todos os itens do CheckListBox
for i := 0 to Pred(Self.clbModificador.Count) do
begin
//Verificamos se a opção está marcada
if (Self.clbModificador.Checked[i]) then
begin
//Gravamos a opção em um string auxiliar
sModificador := Self.clbModificador.Items[i];
//Transformamos a string para o tipo enumerado
eModificador := TRegExOption(TypInfo.GetEnumValue(TypeInfo(TRegExOption),sModificador));
//Incluímos o resultado no conjunto
Include(Result,eModificador);
end;
end;
end;
Listagem 3: Método ObterModificadores

Os modificadores

Com o aplicativo desenvolvido e funcional, vamos entender, enfim,


cada um dos modificadores. São sete os modificadores, que podem ser
usados em conjunto ou isoladamente.

Nenhuma opção marcada: roNone

Esta opção indica que nenhuma opção está marcada. Porém, usá-la
em conjunto com outras opções não as anula. Portanto, não se percebe um
uso prático para este modificador, pois equivale a passar o conjunto vazio.

Ativar combinação insensível à caixa tipográfica: roIgnoreCase

No artigo anterior conhecemos o grupo modificador de modo


representado pelas expressões: (?i) e (?-i)

O que estiver entre esses dois átomos será combinado com maiúsculo
ou minúsculo. Mas se esta regra se aplicar a toda a RegEx você pode usar o
modificador roIgnoreCase.

Cópia pessoal de:


36 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 3: Exemplo do roIgnoreCase

Ativar modo de captura explícita: roExplicitCapture

Ainda no artigo anterior vimos que os agrupadores têm as funções de


agrupar e capturar. A captura é um recurso caro e o seu uso só tem sentido
com o uso de referências anteriores, ou se usarmos o resultado na linguagem
hospedeira. Para usar um grupo sem a função de captura podemos usar a
expressão: (?: subexpressão) .

Porém, dependendo do tamanho da sua RegEx, esta notação a poluirá


visualmente tornando-a mais confusa. Como opção, então, temos o
modificador roExplicitCapture que desliga a função de captura de todos os
grupos, a não ser que ele seja um grupo nomeado, cuja expressão é: (?<nome>
subexpressão).

No exemplo abaixo temos uma lista de pássaros e por algum motivo


queremos apenas os que tem nome composto repetido e que seja
classificado como “feio” ou “bonito”.

Cópia pessoal de:


37 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 4: Exemplo do roExplicitCapture

A RegEx utilizada foi: (?<passaro>\w*)-\k<passaro>[ ]é[


](bonito|feio)

Perceba que usamos dois grupos, um para pegar o nome do pássaro e


outro para oferecer uma alternância.

1º Grupo (?<passaro>\w*) Grupo de captura nomeado


2º Grupo (bonito|feio) Grupo de alternância

Por fim, para tirar proveito do valor capturado pelo primeiro grupo
usamos o átomo:

\k<passaro> Este é uma referência anterior a um grupo nomeado

Perceba ainda na TreeView que o valor retornado pelo segundo grupo


não consta no resultado, situação que muda quando desmarcamos a opção
roExplicitCapture.

Habilitar comentários de linha: roIgnorePatternSpace

Algumas RegEx podem realmente ficar complexas. Provavelmente


comentários certos nos lugares certos ajudarão bastante a entender o objetivo

Cópia pessoal de:


38 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

de uma RegEx sem precisar analisar átomo a átomo. Isso é possível com o
modificador roIgnorePatternSpace.

Esse modificador faz com que o motor RegEx ignore os caracteres de


espaço na RegEx, exceto os que estiverem dentro das classes de caracteres.
Portanto, deve-se tomar um cuidado especial se o caractere de espaço fizer
parte da sua RegEx, envolvendo-a em uma classe de caracteres.

Com isso, você pode quebrar a sua RegEx em linhas e ao final de cada
linha iniciar um comentário com o símbolo de tralha (#).

Na figura 5 um exemplo simples de análise de um retorno de um


comando ping. A RegEx sem os comentários seria: tempo(.*)[ ](.*)

Figura 5: Exemplo do roIgnorePatternSpace

Compilar a RegEx: roCompiled

Em vários momentos eu cito o motor RegEx, que é o algoritmo


responsável pelo processamento da RegEx. Basicamente ela analisa a RegEx e
varre o texto alvo tomando as melhores decisões possíveis. Dependendo do
cenário o desempenho pode não ser satisfatório.

Cópia pessoal de:


39 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Uma forma de melhorar isso é compilando a RegEx, onde é criado um


mapa prévio com todos os caminhos possíveis que a RegEx poderá tomar. Isso
torna a inicialização mais lenta, porém torna as pesquisas, em especial as
repetitivas, mais rápidas.

Cópia pessoal de:


40 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Tratamento de múltiplas linhas: roMultiLine

Primeiramente temos que ter consciência de que o texto alvo é


meramente uma string que pode ou não ter quebra de linhas lógicas. Isso é
um problema relevante se tratarmos arquivos gerados no Linux por exemplo.

No nosso dia a dia Delphi com Windows, o comum é tratarmos textos


com o EOL (end of line) representados por CR+LF, que no Delphi corresponde
a #13#10.

Como visto no primeiro artigo, temos dois meta-caracteres âncoras que


representam o início de linha e o fim de linha, respectivamente representados
por ^ e $ . O modificador roMultiLine justamente influi no comportamento
destes meta-caracteres.

Para exemplificar isto, vamos considerar uma lista de telefone, onde


queremos o DDD que são os dois primeiros dígitos de cada linha.

Figura 6: Exemplo de busca em múltiplas linhas sem o roMultiLine

Perceba na figura 6, que sem o roMultiLine retornou-se apenas um


resultado enquanto que com o roMultiLine vieram todos os resultados
desejados:

Cópia pessoal de:


41 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 7: Exemplo de busca em múltiplas linhas com o roMultiLine

O mesmo comportamento se aplica ao meta-caractere $ .

Tratamento de linha simples: roSingleLine

Em algumas ocasiões você precisará tratar textos com quebras de


linhas como se fosse uma só. Um bom exemplo é a análise de um protocolo de
comunicação como, por exemplo, o HTTP. Para isso usamos o modificador
roSingleLine que influi no significado do meta-caractere ponto: .

A princípio o meta-caractere ponto combina com qualquer caractere.


Mas se tentarmos analisar um texto com quebra de linhas não seremos bem
sucedidos, a não ser que usemos o roSingleLine.

Na figura 8 estamos analisando um cabeçalho HTTP com o objetivo de


capturar o código de retorno bem como o tamanho do conteúdo.

Cópia pessoal de:


42 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 8: Exemplo de busca em múltiplas linhas sem o roSingleLine

Não obtivemos sucesso, pois a motor RegEx não considerou a quebra


de linha (#13#10) ao fazer o processamento, gerando falha. Para
conseguirmos o nosso objetivo, devemos sinalizar ao motor RegEx para
considerar a quebra de linha no meta-caractere ponto:

Figura 9: Exemplo de busca em múltiplas linhas com o roSingleLine

Cópia pessoal de:


43 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Tipos para Manipulação de ReGex no Delphi

A primeira observação que devemos fazer sobre os tipos que lidam com
Expressão Regular no Delphi XE2 é que elas não são classes e sim records com
métodos. É importante perceber isso para não fazermos códigos
desnecessários imaginando que devemos necessariamente instanciar estas
supostas classes e consequentemente liberá-las da memória.

Vamos aos tipos:

Nome Tipo Propósito


TRegEx Record É o tipo responsável pela aplicação da RegEx em
um alvo
TMatch Record Representa uma combinação
TMatchCollection Record Representa uma coleção de combinações
TGroup Record Representa um agrupamento
TGroupCollection Record Representa uma coleção de agrupamento
TMatchEvaluator Pointer É um ponteiro para um método que será
acionado a cada combinação com sucesso em
uma operação de replace.

Cópia pessoal de:


44 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Tipo: TRegEx

O tipo TRegEx é o record que efetivamente aplica uma Expressão


Regular em um determinado alvo.

Possui vários métodos e ao longo dos artigos conhecemos alguns deles.


Esses métodos por sua vez são sobrecarregados tendo várias opções de uso.

A primeira dúvida recorrente é se devemos ou não inicializar o TRegEx. A


princípio não precisamos. Só teremos alguma vantagem em fazê-lo em caso
de uso repetitivo no mesmo algoritmo. Eu prefiro o termo inicializar ao termo
instanciar, pois como dito anteriormente não se trata de uma classe e sim de
um record com métodos.

Veja dois exemplos, com e sem a inicialização.

procedure TfExemplo.Button1Click(Sender: TObject);


var
_RegEx : TRegEx;
bRet : Boolean;
begin
_RegEx := TRegEx.Create('Delphi',[]);
bRet := _RegEx.IsMatch('O Delphi é sensacional!');
ShowMessage('Sucesso: ' + BoolToStr(bRet,True));
end;
Listagem 1: Exemplo de uso do tipo TRegEx com inicialização

procedure TfExemplo.Button2Click(Sender: TObject);


var
bRet : Boolean;
begin
bRet := TRegEx.IsMatch('O Delphi é sensacional!','Delphi',[]);
ShowMessage('Sucesso: ' + BoolToStr(bRet,True));
end;
Listagem 2: Exemplo de uso do tipo TRegEx sem inicialização

O resultado é o mesmo. A única vantagem no caso de uma


inicialização é em um código com loop, pois alguns passos seriam poupados.
Na Listagem 3 temos um exemplo onde uma suposta listagem de nomes é
analisado dando-se um tratamento especial às linhas que contêm o nome
“Fernanda”:

Cópia pessoal de:


45 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

procedure TfExemplo.Button3Click(Sender: TObject);


var
slResultado : TStringList;
_arquivo : TextFile;
_RegEx : TRegEx;
sLinha : string;
bRet : Boolean;
_tempo : TStopwatch;
begin
slResultado := nil;
try
slResultado := TStringList.Create;
_RegEx := TRegEx.Create('\bFernanda\b',[roIgnoreCase,roCompiled]);
AssignFile(_arquivo,'.\listagem.txt');
Reset(_arquivo);
_tempo := TStopwatch.Create;
_tempo.Start;
while not Eof(_arquivo) do
begin
Readln(_arquivo,sLinha);
bRet := _RegEx.IsMatch(sLinha);
if (bRet) then
begin
slResultado.Add(sLinha);
end;
end;
_tempo.Stop;
CloseFile(_arquivo);
finally
if (Assigned(slResultado)) then
begin
Memo1.Text := slResultado.Text;
slResultado.Free;
end;
ShowMessage('Tempo: ' + IntToStr(_tempo.ElapsedMilliseconds));
end;
end;
Listagem 3: Exemplo de uso do tipo TRegEx com inicialização em um loop

Veja que usamos o modificar roCompiled com o objetivo de tornar a


aplicação da RegEx ainda mais rápida. Abordei este assunto no artigo
anterior.

Método: TRegEx.IsMatch

Nos exemplos até aqui usamos o método IsMatch que simplesmente


indica se houve uma combinação (True) ou se não houve combinação
(False). Não temos, portanto, nenhuma informação adicional. É muito útil para
validação. Um uso prático é programar no OnExit de um TEdit por exemplo,
validando um e-mail, endereço IP, URL ou qualquer outra necessidade.

Método: TRegEx.Escape

Retorna a RegEx em questão com os meta-caracteres escapados, ou


seja, precedidos por barra invertida (\). Caso em uma busca você não queira
considerar os meta-caracteres, mas sim fazer uma busca literal, o método
Escape, então, facilita esta tarefa.

Cópia pessoal de:


46 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Método: TRegEx.Match

O método Match retorna um TMacth (explicado mais a frente), que


representa uma combinação. Por retornar apenas uma combinação a função
retorna assim que encontrar a primeira combinação.

Por ser um método sobrecarregado existem algumas possibilidades


interessantes:

function Match(const Input: string): TMatch; overload;

Esta versão é útil no caso de um TRegEx inicializado pois requer apenas


o texto alvo.

function Match(const Input: string; StartPos: Integer): TMatch; overload;

Esta versão dá a possibilidade de aplicarmos a RegEx a partir de uma


determinada posição do texto alvo.

function Match(const Input: string; StartPos, Length: Integer): TMatch; overload;

Já esta versão dá a possibilidade de limitar a abrangência de


aplicação da RegEx no texto alvo.

class function Match(const Input, Pattern: string): TMatch; overload; static;

Esta versão pede o texto alvo e a RegEx a ser aplicada.

class function Match(const Input, Pattern: string; Options: TRegExOptions):


TMatch; overload; static;

Por fim, esta versão pede o texto alvo, a RegEx e os modificadores a


serem aplicados.

Método: TRegEx.Matches

O método Matches retorna um TMatchCollection (que será explicado


mais a frente), ou seja, uma coleção de TMatch ou combinações. Portanto, o
método retornará apenas quando todo o texto alvo for analisado.

Possui as mesmas possibilidades de TRegEx.Match exceto a de limitar a


abrangência de aplicação da RegEx no texto alvo (parâmetro Length).

Método: TRegEx.Replace

Cópia pessoal de:


47 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

O método Replace se mostra extremamente útil para busca e


substituição de texto. Muitos argumentam que a função StringReplace já faz
isso. Mas o detalhe é que podemos substituir os textos que combinam com
uma RegEx, enquanto que o StringReplace só trabalha com texto literal.

Assim, como nos outros métodos existem várias possibilidades, porém no


nosso exemplo vamos nos concentrar na mais básica.

Em um novo aplicativo, proponha-se o seguinte layout:

leRegEx:
TLabeledEdit

leNovoTexto:
TLabeledEdit

bProcessar:
TButton

mTextoOriginal: mNovoTexto:
TMemo TMemo

Figura 1: Proposta de layout de aplicativo de estudo

Em seguida o código do evento OnClick do botão bProcessar:

procedure TfPrincipal.bProcessarClick(Sender: TObject);


var
sTexto : string;
sRegEx : string;
sNovoTexto : string;
begin
sTexto := mTextoOriginal.Text; //Texto original
sRegEx := leRegEx.Text; //Expressão regular
sNovoTexto := leNovoTexto.Text; //Novo texto

//Resultado final
mNovoTexto.Text := TRegEx.Replace(sTexto,sRegEx,sNovoTexto);
end;
Listagem 4: Exemplo de utilização do método Replace

Por fim, um exemplo onde estamos substituindo os nomes “Fernanda” e


“Fernandinha” por “Fefezinha”:

Cópia pessoal de:


48 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 2: Aplicação do método Replace

Vimos acima uma aplicação simples do método replace. Mas existe


alguns métodos sobrecarregados muito interessantes que pedem um
TMatchEvaluator. Este tipo é um ponteiro para um método com a seguinte
assinatura:

function(const Match: TMatch): string

Ela nos permite avaliar a combinação encontrada e determinar por


qual texto ele será substituído.

Aproveitando o aplicativo que criamos, vamos adicionar mais um botão


(bEvaluator) e codifica-lo como se segue. O objetivo é criarmos meta-tags,
encerrados por sinal de percentual (%) que será substituído pelo valor correto.

procedure TfPrincipal.bEvaluatorClick(Sender: TObject);


var
sTexto: string;
sRegEx: string;
sNovoTexto: string;
begin
sTexto := mTextoOriginal.Text;
sRegEx := leRegEx.Text;
sNovoTexto := leNovoTexto.Text;

mNovoTexto.Text := TRegEx.Replace(sTexto, sRegEx, Self.Avaliador);


end;
Listagem 5: Exemplo de utilização do método Replace com TMatchEvaluator

A seguir, o código do método Avaliador que estamos passando como


parâmetro do Replace:

Cópia pessoal de:


49 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

function TfPrincipal.Avaliador(const Match: TMatch): string;


begin
if (Match.Value = '%NOME%') then
begin
Result := 'Mário Guedes';
end
else if (Match.Value = '%EMAIL%') then
begin
Result := 'jmarioguedes@gmail.com';
end;
end;
Listagem 4: Exemplo de um método TMatchEvaluator

Por fim, o exemplo em execução:

Figura 3: Aplicação do método Replace com um TMatchEvaluator

Método: TRegEx.Split

Com o método Split conseguimos dividir o texto alvo usando uma RegEx
como separador. Ainda usando o nosso aplicativo de estudo, vamos colocar
mais um botão (bSplit) e codificar como segue:

procedure TfPrincipal.bSplitClick(Sender: TObject);


var
sTextoAlvo : string;
sSeparador : string;
aResultado : TArray<string>;
sItem : string;
begin
sTextoAlvo := mTextoOriginal.Text;
sSeparador := leRegEx.Text;

mNovoTexto.Clear;
aResultado := TRegEx.Split(sTextoAlvo, sSeparador);
for sItem in aResultado do
begin
mNovoTexto.Lines.Add(sItem);
end;
end;
Listagem 5: Exemplo de utilização do Split
Cópia pessoal de:
50 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

No exemplo abaixo, estamos utilizando a tag <br> como separador de


campo:

Figura 4: Exemplo de utilização do Split

Tipo: TMatch

O tipo TMatch representa uma combinação. Este tipo nos oferece as


seguintes informações:

Propriedade Propósito
Success Indica que houve sucesso na combinação
Index Posição em que a combinação se inicia no texto
alvo
Length Tamanho do texto que combinou com a RegEx
Value Texto que combinou com a RegEx
Groups Coleção de agrupamentos que fazem parte da
combinação

Temos ainda dois métodos, NextMatch e Result:

Método: TMatch.NextMatch

O método NextMatch nos permite ir avançando nas combinações


gradualmente, sendo que podemos interromper conforme a necessidade.
Cópia pessoal de:
51 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

procedure TfPrincipal.bNextMatchClick(Sender: TObject);


var
sTexto: string;
sRegEx: string;
_match: TMatch;
begin
sTexto := mTextoOriginal.Text;
sRegEx := leRegEx.Text;

_match := TRegEx.Match(sTexto,sRegEx,[]);
while _match.Success do
begin
mNovoTexto.Lines.Add(_match.Value);
_match := _match.NextMatch;
end;
end;
Listagem 6: Exemplo de utilização do NextMatch

No algoritmo acima estamos buscando apenas cadeias de números


alimentando o TMemo mNovoTexto a cada resultado:

Figura 5: Exemplo de utilização do NextMatch

Cópia pessoal de:


52 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Método: TMatch.Result

O método Result é uma forma de se obter o valor combinado


aplicando-se uma formatação.

Vamos colocar mais um botão (bResult) com o código abaixo:

procedure TfPrincipal.bResultClick(Sender: TObject);


var
sRegEx : string;
sTexto : string;
sFormato : string;
_match : TMatch;
begin
mNovoTexto.Clear;

sRegEx := leRegEx.Text;
sTexto := mTextoOriginal.Text;
sFormato := leNovoTexto.Text;
_match := TRegEx.Match(sTexto,sRegEx,[]);

while (_match.Success) do
begin
mNovoTexto.Lines.Add(_match.Result(sFormato));
_match := _match.NextMatch;
end;
end;
Listagem 7: Exemplo de utilização do Result

No exemplo abaixo, estamos retornando duas informações: DDD e


Telefone, porém retornando a informação já formatada. Perceba que a RegEx
possui dois agrupamentos e que no Result estamos fazendo referência a estes
agrupamentos.

Figura 6: Exemplo de utilização do Result

Cópia pessoal de:


53 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Tipo: TMatchCollection

O TMatchCollection é uma coleção de combinações não havendo


nada de relevante a ser dito sobre ele, a não ser claro, seu funcionamento
básico.

Vale mencionar ainda que o método TRegEx.Matches se diferencia do


TMatch.NextMatch justamente pelo fato do primeiro só retornar quando todas
as combinações forem encontradas, o que pode ser problemático em textos
muito grandes.

Segue o código de mais um botão, o bMatchCollection, onde varremos


a todas as combinações retornadas colocando o texto no TMemo
mNovoTexto.

procedure TfPrincipal.bMatchCollectionClick(Sender: TObject);


var
sAlvo : string;
sRegEx : string;
_collection : TMatchCollection;
i : Integer;
begin
mNovoTexto.Clear;
sAlvo := mTextoOriginal.Text;
sRegEx := leRegEx.Text;

_collection := TRegEx.Matches(sAlvo,sRegEx,[]);
if (_collection.Count > 0) then
begin
for i := 0 to Pred(_collection.Count) do
begin
mNovoTexto.Lines.Add(_collection.Item[i].Value);
end;
end;
end;

O código acima usa o for..to..do mas poderíamos usar tranquilamente o


for..in..do, como no exemplo abaixo:

procedure TfPrincipal.bMatchCollection2Click(Sender: TObject);


var
sAlvo : string;
sRegEx : string;
_collection : TMatchCollection;
_match : TMatch;
begin
mNovoTexto.Clear;
sAlvo := mTextoOriginal.Text;
sRegEx := leRegEx.Text;

_collection := TRegEx.Matches(sAlvo,sRegEx,[]);
if (_collection.Count > 0) then
begin
for _match in _collection do
begin
mNovoTexto.Lines.Add(_match.Value);
end;
end;
end;

Cópia pessoal de:


54 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Tipo: TGroup

O tipo TGroup prove informações sobre os grupos presentes em um


determinado TMatch. As informações que ele oferece são:

Propriedade Propósito
Success Indica o sucesso da combinação pelo agrupamento
Index Indica a posição do texto combinado pelo agrupamento
no texto alvo
Length Indica o tamanho do texto combinado pelo
agrupamento
Value Indica o texto combinado pelo agrupamento

Tipo: TGroupCollection

O tipo TGroupCollection é uma coleção de grupos e o seu uso é


idêntico ao TMatchCollection, não havendo nada a acrescentar.

Cópia pessoal de:


55 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Abordagens Avançadas com RegEx

Grupo de condição: (?(<Retro referência>)<ER verdadeiro>|<ER


falso>)

Pois é. Não bastassem todas as possibilidades que vimos até aqui, eis
que surge a de usarmos uma condição booleana: if..then..else.

Nesta construção é testado se um grupo anterior combinou ou não. Se


sim, é aplicada uma RegEx no restante do texto, senão é aplicada outra
RegEx. Perceba que a parte “else” é opcional.

Suponhamos uma lista simples de pessoas com nome, profissão e idade.


Nosso objetivo é simplesmente combinar o nome e a idade respectiva de
cada pessoa.

É um problema simples, com várias possibilidades de solução.

O fato é que para o nome a expressão poderia ser algo parecido com
(.*?), enquanto que para a idade o mais adequado é (\d*). A primeira
possibilidade que nos surge é fazermos dois processamentos individuais. E é
para este fato que quero chamar a atenção: o grupo de condição pode
resolver este problema:

Figura 1: Aplicação do grupo de condição

Cópia pessoal de:


56 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Percebemos dois resultados distintos: Um para quando o “grupo 1”


combinou e outro para quando não combinou. Vamos analisar a RegEx em
questão:

Interpretação Átomo
 Grupo normal com ou sem
(^NOME:)?
ocorrência
 Início de grupo modificado (?
 Retro referência ao grupo 1 (1)
 RegEx para verdadeiro (.*?),
 Indicação da parte else |
 RegEx para falso (\d*)
 Fim de grupo modificado )

Isso então abre diversas possibilidades. O único senão é o retorno dos


grupos. Veja que o primeiro resultado retorna dois grupos, ao passo que o
segundo três grupos. Isso realmente pode ficar confuso na linguagem
hospedeira.

Grupo olhar em volta (look around)

Há momentos em que queremos combinar com um determinado


trecho somente se este for precedido ou sucedido por um texto em específico,
porém não queremos que este texto específico faça parte da combinação.

Essa facilidade é especialmente útil em rotinas de substituição de texto.


Temos, então, quatro possibilidades:

Tipo Átomo Explicação


Olhar adiante (look (?=<RegEx>) Bem sucedida se combinar à
ahead) direita
Olhar adiante negativo (?!<RegEx>) Bem sucedida se não combinar à
direita
Olhar para trás (look (?<=<RegEx>) Bem sucedida se combinar à
behind) esquerda
Olhar para trás negativo (?<!<RegEx>) Bem sucedida se não combinar à
esquerda

Imaginemos um fragmento HTML simples, que possui vários elementos e


por algum motivo queremos apenas as que estiverem entre as tags <b> e
<\b>, porém não queremos que estas tags façam parte do resultado. A
solução é a seguinte:

Cópia pessoal de:


57 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 2: Aplicação dos grupos “Olhar em Volta”

Conseguimos retornar apenas “Linha 2” sem incluir as tags. Aqui


usamos o “olhar adiante” e o “olhar para trás” positivos, ou seja, a RegEx
combinou quando as condições combinaram.

Mas pode ser que não desejamos uma combinação, quando esta for
precedida ou sucedida por um determinado valor. Vamos imaginar uma lista
de nome e sobrenome onde queremos retornar apenas o sobrenome de uma
determinada pessoa:

Cópia pessoal de:


58 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Figura 3: Aplicação dos grupos “Olhar em Volta”

E se quisermos o resultado inverso basta uma mudança simples:

Figura 4: Aplicação dos grupos “Olhar em Volta”

Isto tudo, se aplicado a uma rotina de substituição de texto, faz com


que este processo seja cirúrgico, pois conseguiríamos, por exemplo, mudar de
GUEDES para SILVA somente as entradas realmente desejadas.

Cópia pessoal de:


59 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Vale agora uma observação muito importante: Estas construções não


consome o texto combinado. No exemplo abaixo, usei o GUEDES duas vezes.
Não que seja uma construção exatamente útil, mas exemplifica bem o
conceito. A construção foi necessária, pois o GUEDES não foi consumido pelo
(?=GUEDES):

Figura 5: Aplicação dos grupos “Olhar em Volta”

Por fim, encerrando este assunto, podemos usar os grupos “olhar em


volta” em um grupo condicional. Se a combinação for bem sucedida aplica-
se uma RegEx, enquanto que se não for bem sucedida aplica-se outra RegEx.

Cópia pessoal de:


60 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Abreviações de caracteres

Obviamente alguns caracteres são difíceis de representar, como a


quebra de linha por exemplo. Segue uma tabela com os meta-caracteres
especiais que representam esses casos:

Abreviação Significado
\a Alerta
\b Backspace
\e Escape
\f Alimentador
\n Quebra de linha
\r Retorno de carro
\t Tabulação
horizontal
\v Tabulação
vertical

De toda a tabela certamente usaremos com mais frequência o \r\n


que equivale a uma quebra de linha padrão no Windows, e que no Delphi é
equivalente à #13#10.
Mas tome um cuidado especial com estas abreviações especialmente
se estiver analisando texto gerados em outros sistemas operacionais.

Abreviações de classes de caracteres

Algo importante a ser considerado na construção de uma RegEx é a


limitação de abrangência de um determinando átomo. Se quisermos, por
exemplo, que uma posição case apenas com números de zero a nove
poderíamos usar:

(0|1|2|3|4|5|6|7|8|9)

Isso não parece agradável de ler nem muito menos de aplicar. Com a
classe de caractere a RegEx passa a ser:

[0123456789]

Melhorou. Mas que tal esta construção agora?

[0-9]

Ficou bem melhor. Mas, para este caso em específico, ou seja,


combinar com qualquer número de zero a nove, pode-se usar simplesmente
uma abreviação de classe para dígitos:

Cópia pessoal de:


61 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

\d

Repare que o ponto, que casa qualquer caractere, é por si só uma


abreviação de classe. É equivalente a algo como:

[abcdefghijklmnopqrstuvwxyzABC ...]

Exatamente: Não fosse o ponto e seriamos obrigados a digitar todos os


caracteres possíveis em uma determinada posição. Mas existem outras
abreviações de classe, a seguir conheceremos as mais usuais:

Abreviação Significado
\d Dígito, equivalente à [0-9]
\D Não dígito, equivalente à [^0-9]
\w Caractere de palavra, equivalente à [a-ZA-Z0-9_]
\W Caractere de não palavra, equivalente à [,.!@#$ ...]
\s Caractere de espaço em branco, equivalente à [
\f\n\r\t\v]
\S Caractere não de espaço em branco, equivalente à
[a-zA-Z...]

Com isso, podemos refinar ainda mais a nossa busca sem maiores
obstáculos como tempo e tamanho da RegEx.

Problemática de acentuação e outras línguas

Um problema recorrente que temos com RegEx é com acentuação.


Fica muito ruim de repente ficar declarando classes de caracteres para
[ãÃõÕçÇ] e por ai vai. Isso acontece porque o motor RegEx trabalha
essencialmente com a tabela ASCII, do byte 0 ao byte 127 (7 bits), deixando
de fora, entre outros, os caracteres acentuados.

No exemplo que segue temos a palavra CORAÇÃO e percebemos que o


Ç e o à não fazem parte do resultado:

Figura 6: Aplicação da abreviação de classe \w

Cópia pessoal de:


62 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

É um problema sério, que muitas vezes é solucionado com o meta-


caractere ponto. Mas o ponto pode ser abrangente demais. Para resolver isto
temos duas soluções possíveis: as classes de caracteres POSIX (que não
funciona no Delphi) ou trabalhar diretamente com as propriedades Unicode.

Cópia pessoal de:


63 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Classes de caracteres POSIX

As classes de caracteres POSIX infelizmente não funcionam a contento


no Delphi, mas pode ser uma solução em outras ferramentas. As classes POSIX
se baseiam nas configurações regionais do sistema operacional corrente para
determinar o que são dígitos, letras, pontuação e etc.

Segue uma tabela com as classes POSIX mais comuns:

POSIX Significado
[:upper:] Letras maiúsculas
[:lower:] Letras minúsculas
[:alpha:] Letras
[:alnum:] Letras e números
[:digit:] Números
[:xdigit:] Números hexadecimais
[:punct:] Sinais de pontuação
[:blank:] Espaço e tabulação
[:space:] Caracteres em branco (espaço, tabulação, retorno de
carro e etc.)
[:cntrl:] Caracteres de controle
[:graph:] Caracteres imprimíveis
[:print:] Caracteres imprimíveis e o espaço

Perceba que uma classe POSIX deve ser usada dentro de uma classe
de caracteres maior, como no exemplo abaixo:

Figura 7: Aplicação da abreviação de classe POSIX [[:alpha:]]

Ainda no exemplo acima percebe-se que o [:alpha:] não incluiu o Ç


e o Ã, como deveria.

Cópia pessoal de:


64 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Trabalhando com Unicode

A solução mais segura para trabalhar com caracteres que não estão na
tabela ASCII básica é utilização da tabela Unicode (http://www.unicode.org).

A tabela Unicode pode representar todos os caracteres concebidos


pela humanidade. Muito além de representar os caracteres, a codificação
Unicode prevê os atributos destes caracteres, como caixa alta ou caixa baixa
por exemplo.

Para trabalharmos com os caracteres na tabela Unicode usamos o


meta-string \p{atributo} para combinar com caracteres que possui o
atributo em questão e \P{atributo} para combinar com caracteres que não
possui o atributo em questão.

Solucionando, então, o problema com a palavra CORAÇÃO temos:

Figura 8: Aplicação de uma meta-string para Unicode

A propriedade \p{Lu} se refere às letras maiúsculas: L de letter, u de


upper.

Perceba que se precisar lidar com escritos em outras línguas, a solução


passará, necessariamente, pelo Unicode.

Por falar em outras línguas, segue um exemplo de aplicação da RegEx


em um texto árabe:

Figura 9: Exemplo de um texto em árabe


Cópia pessoal de:
65 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

O texto é “Isto está escrito em árabe” e a RegEx é “escrito”.


Mas, e se precisarmos destacar cada palavra do texto? O \w é inviável neste
caso. Usamos, então, a RegEx \p{L}* que simplesmente significa: uma letra
em qualquer quantidade:

Figura 10: Exemplo de um texto em árabe com a aplicação de um meta-string


Unicode

Segue uma tabela com alguns meta-strings interessantes para se


trabalhar com Unicode:

Meta- Significado
string
\p{L} Símbolos considerados letras.
\p{Lu} – Símbolos considerados letras maiúsculas
\p{Ll} – Símbolos considerados letras minúsculas
\p{M} Símbolos que devem vir sobre outro caractere base, como
acento.
\p{Z} Símbolos de separação, mas sem representação visual
(espaço).
\p{S} Símbolos diversos como cifrão e trema.
\p{N} Símbolos que representam números.
\p{P} Símbolos que representam pontuação como exclamação e
interrogação.
\p{C} Símbolos diversos.

Esta tabela é básica. Existem dezenas de possibilidades.

Cópia pessoal de:


66 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Escape octal - \<número>

Ainda na linha dos caracteres difíceis de representar, caso você se


depare com um texto com caracteres “estranhos”, mas que influencia no seu
resultado, você pode buscar este caractere pelo seu código na tabela ASCII,
porém na base octal. No exemplo que segue o texto foi colocado do MS Excel
e ao invés de espaços temos um caractere de tabulação:

Figura 11: Texto colocado a partir do MS Excel e uma RegEx que não combina

Perceba na imagem que a RegEx NOME:[ ]+ não combina, apesar de


aparentemente haver espaços após NOME: .

Mas na verdade o que existe é um caractere de tabulação. Então


podemos mudar a RegEx para:

Figura 12: RegEx utilizando um escape octal

Poderíamos ter usado o \t para o mesmo efeito, mas usamos \011


(que equivale a nove na base octal) para demonstrar a facilidade.

Cópia pessoal de:


67 de 68
Jaison Santos | jailson.santos@g4solutions.com.br
Expressões Regulares com Delphi

Âncoras e outras asserções de largura zero

Finalizando o artigo, vamos falar sobre as âncoras. Os meta-caracteres


do tipo âncora não combinam com um texto propriamente dito, mas sim com
uma posição no texto. Neste grupo cabe inclusive os grupos “olhar em volta”
do qual falamos no começo deste artigo.

Já conhecemos o circunflexo e o cifrão que combinam com o início e


fim de linha respectivamente. Porém, o comportamento destes meta-
caracteres muda com o uso do modificador roMultiline e roSingleLine, o
que pode prejudicar algum objetivo. Para resolver isto temos as seguintes
meta-strings:

Meta- Objetivo
String
^ Combina com o início de uma string ou linha, de acordo com
o modificador.
$ Combina com o final de uma string ou linha, de acordo com o
modificador.
\A Combina sempre com o início de uma string.
\Z Combina sempre com o final de uma string.
\z Combina sempre com o final de uma string.
\b Combina com borda de palavra.
\B Combina com não borda de palavra.

Cópia pessoal de:


68 de 68
Jaison Santos | jailson.santos@g4solutions.com.br

Você também pode gostar