25
Regular Expression por Fabio R. Galuppo Manipulação de texto, independente do formato no qual ele se apresenta, é uma tarefa comum nas aplicações de qualquer sistema operacional. Os mais sofisticados softwares utilizam-se deste recurso, onde sempre esteve presente. O .NET Framework suporta regular expression para auxiliar nesta tarefa. Ela destaca-se devido ao seu poder em processar textos. Regular expression é popular e sua utilização comum em aplicações escritas Perl. No entanto, as funcionalidades de uma regular expression podem ser encontradas de outras maneiras como, por exemplo, em classes C++, no Framework e também em System.Text.RegularExpressions, onde há classes dedicadas para o uso deste recurso. O que é regular expression ? É uma linguagem representada por caracteres e metacaracteres os quais fornecem poder e flexibilidade no processamento de texto. Através da expressão“pattern-matching” é possível, rapidamente, interpretar uma grande quantidade de textos e efetuar diversas operações, tais como, buscar informações e padrões, apagar textos, extrair valores, entre outros. O trabalho de interpretação do texto é feito de acordo com a expressão. Já a manipulação é feita de forma amigável através das classes, sendo, na maioria das vezes, expostas em coleções para serem manipuladas, ou seja, as aplicações que fazem manipulação de texto, e que não possuem um layout bem definido, por exemplo, XML, poderão escrever aplicações mais inteligentes, e se houver mudança no layout a adaptação da aplicação é mínima. Nos casos gerais recomenda-se somente atualizar a regular expression. Se fizermos uma análise primária, pode-se dizer que as classes interagindo com a regular expression trazem um poder semelhante ao das tradicionais classes de XML, haja vista no que diz respeito ao modelo de programação responsável pelo processamento dos dados.

A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

Manipulação de texto, independente do formato no qual ele se apresenta, é uma tarefa comum nas aplicações de qualquer sistema operacional. Os mais sofisticados softwares utilizam-se deste recurso, onde sempre esteve presente. O .NET Framework suporta regular expression para auxiliar nesta tarefa. Ela destaca-se devido ao seu poder em processar textos.

Regular expression é popular e sua utilização comum em aplicações escritas Perl. No entanto, as funcionalidades de uma regular expression podem ser encontradas de outras maneiras como, por exemplo, em classes C++, no Framework e também em System.Text.RegularExpressions, onde há classes dedicadas para o uso deste recurso.

O que é regular expression ?

É uma linguagem representada por caracteres e metacaracteres os quais fornecem poder e flexibilidade no processamento de texto. Através da expressão“pattern-matching” é possível, rapidamente, interpretar uma grande quantidade de textos e efetuar diversas operações, tais como, buscar informações e padrões, apagar textos, extrair valores, entre outros.

O trabalho de interpretação do texto é feito de acordo com a expressão. Já a manipulação é feita de forma amigável através das classes, sendo, na maioria das vezes, expostas em coleções para serem manipuladas, ou seja, as aplicações que fazem manipulação de texto, e que não possuem um layout bem definido, por exemplo, XML, poderão escrever aplicações mais inteligentes, e se houver mudança no layout a adaptação da aplicação é mínima. Nos casos gerais recomenda-se somente atualizar a regular expression. Se fizermos uma análise primária, pode-se dizer que as classes interagindo com a regular expression trazem um poder semelhante ao das tradicionais classes de XML, haja vista no que diz respeito ao modelo de programação responsável pelo processamento dos dados.

Quando falamos de regular expression é difícil, ou melhor, impossível deixar de citar os metacaracteres, onde todo o potencial e flexibilidade dela são apresentados. Os metacaracteres são usados desde os primórdios do DOS. Mas para alguns ainda resta a pergunta: o que são metacaracteres? Metacaracteres são aqueles caracteres os quais representam algum significado, por exemplo:

C:\> dir *.txt *.cs > output.dat

O comando acima instrui para que no DOS, ou no Command Prompt, seja mostrado todos os arquivos textos e arquivos de programas C# do diretório C:\, e sua saída redirecionada para um arquivo output.dat. Os metacaracteres, neste caso, são: *.txt, *.cs e > (stdout). No caso da regular expression, as expressões podem ter complexidades variáveis como perceberá no uso delas, mas independente do grau de dificuldade, este recurso é altamente recomendado. Livros como: a documentação do Framework e o MSDN fornecem extensas documentações sobre o assunto.

Page 2: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

Construindo uma expressão

Para se construir uma expressão basta selecionar uma série de caracteres e metacaracteres, cujo na maioria dos casos, avaliarão o texto da esquerda para direita. A tabela 1 consiste nos principais metacaracteres, os quais são chamados de classes de caractere, juntamente aos seus significados.

Tabela 1: Classes de CaractereMetacaracter Descrição

. Corresponde a qualquer caractere exceto \n[aeiou] Corresponde a qualquer caractere dentro do grupo de caracteres[^aeiou] Corresponde a qualquer caractere que não está dentro do grupo de caracteres[0-9] Corresponde a qualquer caractere dentro da faixa indicada[0-9A-Z] Corresponde a qualquer caractere dentro da faixa indicada, com intervalo\w Corresponde a qualquer caractere de palavra(word)\W Corresponde a qualquer caractere que não forme palavra(non-word)\s Corresponde a qualquer caractere white-space\S Corresponde a qualquer caractere que não seja white-space\uNNNN Corresponde a um caractere Unicode. Por exemplo: \u00A9 representa ©\d Corresponde a qualquer caractere de dígito. Outra forma é [0-9]\D Corresponde a qualquer caractere que não representa dígito. Outra forma é [^0-9]

Ao utilizar os metacaracteres da tabela 1 forma-se logo abaixo uma regular expression que representa o formato de um ISBN:

\d\u002D\d\d\d\d\u002D\d\d\d\d\u002D\d

A expressão acima pode encontrar num texto um valor como 9-999-123-2, porém não pode encontrar algo como 19-999-123-2 o qual também é um ISBN. Isso resolve-se com o uso do operador |, cujo representa OR. Reescrevendo a regular expression para suportar ambos valores, temos:

\d\u002D\d\d\d\d\u002D\d\d\d\d\u002D\d|\d\d\u002D\d\d\d\d\u002D\d\d\d\d\u002D\d

Sinceramente, se uma regular expression for o que está acima, pergunto: Que vantagem eu obterei, além de encontrar os valores, ou para que escrever expressões monstruosas para adquirir algo? O princípio é esse, mas existem formas de melhorar a instrução acima.

Então o próximo passo é conhecer os quantificadores. Eles são fundamentais na construção da regular expression, principalmente por simplificá-la. Na tabela 2 temos os principais quantificadores com suas respectivas descrições

Tabela 2: QuantificadoresQuantificado

rDescrição

* Corresponde a zero ou mais metacaracteres. Por exemplo: \d* ou [a-z]*+ Corresponde a um ou mais metacaracteres. Por exemplo: \d+ ou [a-z]+? Corresponde a zero ou um metacaracteres. Por exemplo: \d* ou [a-z]*{n} Corresponde a n metacaracteres. Por exemplo: \d{1} ou [a-z]{3}{n,} Corresponde a no mínimo n metacaracteres. Por exemplo: \d{2,} ou [a-z]{1,}{n,m} Corresponde a no mínimo n e no máximo m metacaracteres. Por exemplo: \d{2,4}

Page 3: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

Simplificando, temos a seguinte regular expression representando o ISBN :

\d{1,2}\-\d{4}\-\d{4}\-\d{1}

A regular expression acima fica visualmente mais nítida, bem como apresenta um formato amigável. Também é possível representar caracteres especiais usando a barra como prefixo, por exemplo, \- ou – designa o hífen, para representar uma barra utilize \\.

Para construir uma regular expression básica é necessário conhecer as classes de caractere e os qualificadores.

Usando a classe Regex para manipular uma regular expression

O Framework oferece um grupo de classes as quais são encontradas no namespace System.Text.RegularExpressions. A principal classe para manipulação de uma regular expression é a Regex.

Regex – herdeira da System.Object indica uma regular expression imutável. Seus membros são de instância. Suas propriedades são: Options e RightToLeft. Os principais métodos são: GetGroupNames, GetGroupNumbers, GroupNameFromNumber, GroupNumberFromName, IsMatch, Match, Matches, Replace e Split. O método estático mais significativo é o CompileToAssembly.

Para usar a classe Regex basta fornecer a regular expression num dos construtores ou então nos métodos que a suportam. O código abaixo lê um arquivo texto e procura por valores os quais possuem o formato de ISBN. A figura 1 exibe o texto e o resultado.

Figura 1: Exibe os códigos ISBN usando uma regular expression e a classe Regex

//csc regexISBN.cs

Page 4: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

using System;using System.IO;using System.Text.RegularExpressions;

class ISBNCheck{

static void Main() { //Abre o arquivo texto StreamReader sr = new StreamReader(@"c:\samples\file.txt"); string line;

//Processa o arquivo aberto e lê linha a linha while((line = sr.ReadLine()) != null) { //Cria a expressão a ser avaliada Regex r = new Regex(@"\d{1,2}\-\d{4}\-\d{4}\-\d{1}"); //Verifica se a linha corrente corresponde a regular expression if(r.IsMatch(line)) { Console.WriteLine(line); //Exibe no console } }

sr.Close(); //Fecha o arquivo

}

}

O ponto principal é que para exibir o RG, ao invés do ISBN, é necessário trocar a linha de:

Regex r = new Regex(@"\d{1,2}\-\d{4}\-\d{4}\-\d{1}");

Para:

Regex r = new Regex(@"\d{1,2}.\d{3}.\d{3}-\d{1}");

Na plataforma .NET a regular expression é processada rapidamente, pois ao invés dos dados serem desmembrados em runtime e interpretados, um programa MSIL é gerado on-the-fly utilizando técnicas do CodeDOM, e este programa faz a interpretação da informação.

Outra importante classe é a Match. Ela representa o valor encontrado pela regular expression. Seu uso é requisito quando procura-se mais de uma ocorrência numa única linha, a qual pode ser obtida através da classe/coleção MatchCollection ou através do método NextMatch.

Match – herdeira da System.Text.RegularExpressions.Group indica o resultado simples de uma regular expression. Seus métodos de instância são: NextMatch e Result. Suas principais propriedades são: Groups, Index, Length, Success e Value.

Page 5: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

MatchCollection – herdeira da System.Object indica uma coleção de resultados de uma regular expression, esses resultados podem ser iterados. Seus membros são de instância. Suas principais propriedades são: Count e Item, bem como o principal método é: ToCopy.

A figura 2 mostra o novo arquivo lido e seu resultado, logo abaixo é exibido o código que reproduz este resultado.

Figura 2: Exibe os códigos ISBN usando uma regular expression e várias classes

'vbc regexISBN.vb /out:regexISBNVB /r:System.dll

Imports SystemImports System.IOImports System.Text.RegularExpressions

Class regexISBN

Shared Sub Main() 'Abre o arquivo texto Dim sr as New StreamReader("c:\samples\file2.txt") Dim line as String

'Cria a expressão a ser avaliada Dim r as New Regex("\d{1,2}\-\d{4}\-\d{4}\-\d{1}")

'Processa o arquivo aberto e lê linha a linha line = sr.ReadLine() While(line <> Nothing) Dim mc as MatchCollection = r.Matches(line) 'Obtém todos os resultados Dim m as Match Dim a as Integer

For a = 0 to mc.Count-1 'Percorre pelos resultados encontrados m = mc(a) 'Obtém o Match a partir da coleção Console.WriteLine(m.Value) 'Exibe no console

Page 6: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

Next line = sr.ReadLine() End While

sr.Close() 'Fecha o arquivo

End Sub

End Class

Grupos, Backreferences, Backtracking e Nonbacktracking

O grupo permite capturar e agrupar subexpressões. Um grupo é uma regular expression entre parênteses. Por exemplo, para representar um RG temos pelo menos duas formas 11.111.111 e 11.111.111-1. Sem a utilização do grupo temos:

\d{1,2}\.\d{3}\.\d{3}\-\d{1}|\d{1,2}\.\d{3}\.\d{3}

Reescrevendo a expressão acima para utilizar grupos, temos:

(?<rg>\d{1,2}\.\d{3}\.\d{3})(?<rg>\-\d{1})*

A regular expression acima apresenta dois grupos, o primeiro usa (?<rg>\d{1.2}\.\d{3}\.\d{3}) o qual indica no primeiro grupo que a máscara seja armazenada em <rg> para ser reutilizada na expressão. Na segunda expressão (?<rg>\-\d{1}), o <rg> determina que a máscara da primeira expressão seja reutilizada e o resto forma o complemento da máscara. Se a regular expression continuasse, sempre o valor contido em <rg> apontaria para a primeira máscara. Isso simplifica e reduz o tamanho da expressão.

No exemplo anterior, foi utilizado um marcador <rg> para armazenar um padrão e reutilizá-lo mais tarde. Quando um grupo é usado, um buffer temporário é criado e parte dessa expressão armazena-se. Pode-se desabilitar este buffer ao utilizar os metacaracteres ?:, ?= e ?!. Estes buffers se não forem nomeados como no caso do <rg>, podem ser acessados pelo valor seguido da barra, por exemplo \1. O número máximo de buffers é 99 para uma expressão. O processo denomina-se backreference, e uma de suas utilidades foi empregada no exemplo acima, porém outro caso de uso é na captura de duplicidade.

//jsc /r:System.dll /out:regexSample.exe regexSample.js

import System;import System.Text.RegularExpressions;

var s:String = "100 100 200 300 400 400 500"; //Valor com repetiçõesvar r:Regex = new Regex("(\\d+)\\s\\1"); //Regular expressionvar m:Match;

//Percorre todas as correspondências encontradas pela regular expressionfor(m = r.Match(s); m.Success; m = m.NextMatch()) { Console.WriteLine("0: " + m.Groups[0]); //Exibe o grupo 0 Console.WriteLine("1: " + m.Groups[1]); //Exibe o grupo 1}

Console.Write(r.Replace(s,"$1")); //Substitui as ocorrências $0 por $1

Page 7: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

De acordo com os exemplos abaixo, outras utilizações para grupo e backreference é no desmembramento e na transformação de dados. O primeiro exibe uma transformação de dados, e o segundo um desmembramento.

//csc regexDateTime.cs

using System;using System.Text.RegularExpressions;

class regexDateTime{

static void Main() { //Cria as regular expressions para transformação string sfrom = @"(?<d>\d{1,2})/(?<m>\d{1,2})/(?<y>\d{2,4})\s"; sfrom += @"(?<h>\d{1,2}):(?<min>\d{1,2}):(?<seg>\d{1,2})"; string sto = "Time: ${h}:${min}:${seg} Date: ${d}-${m}-${y}";

//Substitui o primeiro formatado pelo segundo string s = Regex.Replace(DateTime.Now.ToString(), sfrom, sto); Console.Write(s); //Exibe no console }

}

'vbc regexDateTime.vb /out:regexDateTimeVB /r:System.dll

Imports SystemImports System.Text.RegularExpressions

Class regexDateTime

Shared Sub Main() 'Cria a regular expression Dim r as new Regex("(?<dia>\d{1,2})/(?<mes>\d{1,2})/(?<ano>\d{2,4})") Dim m as Match = r.Match(DateTime.Now.ToString())'Procura pelo padrão Console.WriteLine("dia : {0}", m.Groups("dia")) 'Exibe no console Console.WriteLine("mes : {0}", m.Groups("mes")) 'Exibe no console Console.WriteLine("ano : {0}", m.Groups("ano")) 'Exibe no console

End Sub

End Class

Nos programas acima, também foram usados de uma forma ou de outra as classes Group e GroupCollection, na qual possuem as informações sobre de grupos e backreferences. Normalmente para acessar um objeto da classe Group, um objeto da classe GroupCollection recebe um índice contento a backreference e retorna a instância. Por exemplo, para acessar o objeto Group passa-se o valor Groups[“dia”] da coleção.

Group – herdeira da System.Text.RegularExpressions.Capture indica o resultado simples de um grupo de captura. Ele contém nenhuma, uma ou mais strings correspondentes ao padrão fornecido. Seu método estático é: Syncrhonze. Suas propriedades de instância são: Captures, Index, Length, Success e Value.

Page 8: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

GroupCollection – herdeira da System.Object indica uma coleção de resultados de grupos de captura, onde esses resultados podem ser iterados. Seus membros são de instância e suas principais propriedades são: Count e Item. O método chave é: ToCopy.

Quando for necessário encontrar um valor dentro de várias opções é usado o operador |, isto permite a uma regular expression encontrar um ou mais valor correspondente. O uso do operador de alternância ( | ) causa uma análise de valores, ou backtracking. Na expressão abaixo o formato de data poderá ser encontrado em duas formas:

\d{1,2}(\/|\-)\d{1,2}(\1)\d{4}

Verificando a regular expression com a string abaixo, o mecanismo de regular expression encontra a primeira parte da string. Na segunda a barra é avaliada e o grupo 1 é armazenado com seu conteúdo e avaliado contra o hífen onde não corresponde ao valor resevado. O mecanismo também avalia e re-avalia os dados, no exemplo, ele procura primeiramente pela barra, caso não a encontre, retorna a avaliar com o hífen. No terceiro caso quando o valor 13 é avaliado a formatação inicial corresponde (\d{1,2}), porém o próximo caractere não corresponde, no entanto a leitura é feita duas vezes: uma para encontrar a barra e a outra para o hífen. Segue abaixo o código que avalia a expressão:

10/11/1973 12/10-1912 13.12.1111 01234-567 11-11-1973 12/11/1973

//csc regexTrack.cs

using System; using System.Text.RegularExpressions;

class regexTrack{ static void Main() { string s; s = @"10/11/1973 12/10-1912 13.12.1111 01234-567 11-11-1973 12/11/1973";

//Prepara a regular expression Regex r = new Regex(@"\d{1,2}(\/|\-)\d{1,2}(\1)\d{4}"); Match m; //Percorre todas as correspondências encontradas pela regular expression for(m = r.Match(s); m.Success; m = m.NextMatch()) { Console.WriteLine(m.Value); //Exibe no console } }}

Existem construções as quais não se produzem backtracking, elas são denominadas nonbacktrackings, e constituídas de alguns dos metacaracteres de construção de grupo (?=), (?<=), (?>). Por exemplo, na regular expression \w+(?=\d) o valor encontrado deve ser um ou mais caractere seguido por um dígito. Esta construção não produz backtracking, ou seja, esta instrução não será re-avaliada. Um outro exemplo é a

Page 9: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

construção (?<=20)\d{2}, onde qualquer dígito duplo será avaliado apenas se precedido por 20.

Captura e Grupo de Captura

Um grupo de captura contém os valores encontrados durante o processamento, esses valores são obtidos de acordo com os quantificadores. As classes do Framework as quais os manipulam são o CaptureCollection e Capture. As propriedades Captures, retornam um objeto da classe CaptureCollection, onde está presente nas classes Match e Group.

Capture – herdeira da System.Object indica o resultado simples da captura de uma subexpressão. A captura representa uma substring para uma simples captura processada com sucesso. Suas propriedades de instância são: Index, Length e Value.

CaptureCollection – herdeira da System.Object indica uma coleção de resultados de captura, eles podem ser iterados. Seus membros são de instância. Suas principais propriedades são: Count e Item. O principal método é: ToCopy.

O exemplo abaixo, retirado da documentação do Framework e portado para Managed C++, mostra o uso das classes Capture e CaptureCollection.

//cl regexCaptures.cpp /CLR

#using <mscorlib.dll>#using <System.dll>

using namespace System;using namespace System::Text::RegularExpressions;

void main() { int counter; Match* m; CaptureCollection* cc; GroupCollection* gc;

//Procura pelo agrupamento "Abc" Regex* r = new Regex("(Abc)+"); //Executa a procura m = r->Match("XYZAbcAbcAbcXYZAbcAb"); gc = m->Groups;

//Exibe o número de grupos Console::WriteLine("Captured groups = {0}", gc->Count.ToString());

//Percorre por cada Grupo for (int i=0; i < gc->Count; i++) { cc = gc->Item[i]->Captures; counter = cc->Count; //Exibe o número de capturas dentro do grupo Console::WriteLine("Captures count = {0}", counter.ToString());

Page 10: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

//Percorre por cada captura dentro do grupo for (int ii = 0; ii < counter; ii++) { String* item = cc->Item[ii]->ToString(); String* index = cc->Item[ii]->Index.ToString(); //Exibe a captura e a posição Console::WriteLine("{0} Starts at character {1}", item, index); } }}

Para ignorar um grupo de captura o metacaractere (?:) é utilizado.

((?:\d{1,2})(\/|\-)(?:\d{1,2})(\2)(?:\d{4}))

Processamento de Texto

O poder da regular expression nota-se no processamento de texto. Por exemplo, imagine um arquivo de log com o seguinte formato:

Layout 1: Arquivo de Log

Date Time User IP Web Service Status10/11/2001 10:30:05 FABIOG 123.124.125.126 Customer.Create 20012/12/2001 09:04:13 FABIOG 123.124.125.127 Customer.Delete 200

A regular expression, para obter o valor de cada uma das colunas, apresenta-se conforme exemplo abaixo. Perceba a poderosa combinação de metacaracteres para representar o layout acima:

(?<date>(\d|\/)+)\s(?<time>(\d|\:)+)\s(?<user>(\S+))\s(?<ip>(\d|\.)+)\s(?<ws>(\w+\.\w+)+)\s(?<status>(\d{3})

O código a seguir representa uma aplicação Windows, a qual faz o processamento do arquivo de log do layout 1. A figura 3 exibe o resultado.

//csc regexLog.cs /r:System.Drawing.dll /r:System.Windows.Forms.dll

using System;using System.IO;using System.Text;using System.Text.RegularExpressions;using System.Drawing;using System.ComponentModel;using System.Windows.Forms;

public class frmLogView : System.Windows.Forms.Form{ private System.Windows.Forms.ListView lvwData; private System.Windows.Forms.OpenFileDialog openFile; private System.Windows.Forms.Label lblFile; private System.Windows.Forms.MainMenu mainMenu; private System.Windows.Forms.MenuItem mnuSeparator; private System.Windows.Forms.MenuItem mnuFile; private System.Windows.Forms.MenuItem mnuOpen; private System.Windows.Forms.MenuItem mnuExit;

Page 11: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

private System.Windows.Forms.Button butRefresh;

public frmLogView() { this.lvwData = new System.Windows.Forms.ListView(); this.openFile = new System.Windows.Forms.OpenFileDialog(); this.lblFile = new System.Windows.Forms.Label(); this.mainMenu = new System.Windows.Forms.MainMenu(); this.mnuFile = new System.Windows.Forms.MenuItem(); this.mnuOpen = new System.Windows.Forms.MenuItem(); this.mnuSeparator = new System.Windows.Forms.MenuItem(); this.mnuExit = new System.Windows.Forms.MenuItem(); this.butRefresh = new System.Windows.Forms.Button(); this.SuspendLayout();

//ListView this.lvwData.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; this.lvwData.Location = new Point(8, 40); this.lvwData.Size = new System.Drawing.Size(272, 187);

//Label this.lblFile.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; this.lblFile.BorderStyle = BorderStyle.Fixed3D; this.lblFile.Location = new System.Drawing.Point(8, 8);

this.lblFile.Size = new Size(200, 24);

//MainMenu this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[]{this.mnuFile}); //mnuFile this.mnuFile.MenuItems.AddRange(new MenuItem[]{this.mnuOpen, this.mnuSeparator, this.mnuExit}); this.mnuFile.Text = "&File";

//mnuOpen this.mnuOpen.Text = "&Open"; this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click);

//mnuSeparator this.mnuSeparator.Text = "-";

//mnuExit this.mnuExit.Text = "&Exit"; this.mnuExit.Click += new System.EventHandler(this.mnuExit_Click);

//Button this.butRefresh.Anchor = AnchorStyles.Top | AnchorStyles.Right; this.butRefresh.Location = new Point(216, 8); this.butRefresh.Size = new Size(64, 23); this.butRefresh.Text = "Refresh"; this.butRefresh.Click += new System.EventHandler(this.butRefresh_Click);

//Form this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(286, 234); this.Controls.AddRange(new System.Windows.Forms.Control[]{this.butRefresh, this.lblFile, this.lvwData}); this.MaximizeBox = false; this.Menu = this.mainMenu;

Page 12: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

this.MinimizeBox = false; this.Text = "Log Viewer"; this.Load += new System.EventHandler(this.frmLogView_Load); this.ResumeLayout(false); }

[STAThread] static void Main() { Application.Run(new frmLogView()); //Inicia a aplicação com o form }

private void mnuOpen_Click(object sender, System.EventArgs e) { //Abre a OpenFile Dialog e verifica se o botão Open foi escolhido if(openFile.ShowDialog() == DialogResult.OK) { lblFile.Text = openFile.FileName; //Nome completo do arquivo butRefresh_Click(this, null); //Executa o método do botão

} }

private void frmLogView_Load(object sender, System.EventArgs e) { //Prepara a ListView ColumnHeader[] h = new ColumnHeader[6]; //Define o cabeçalho

for(int a = 0; a < h.Length; ++a) h[a] = new ColumnHeader();

h[0].Text = "Date"; h[1].Text = "Time"; h[2].Text = "User"; h[3].Text = "IP"; h[4].Text = "Web Service"; h[5].Text = "Status";

for(int a = 0; a < h.Length; ++a) lvwData.Columns.Add(h[a]);

lvwData.View = View.Details; //Define a visualização }

private void mnuExit_Click(object sender, System.EventArgs e) { Application.Exit(); //Finaliza a aplicação }

private void butRefresh_Click(object sender, System.EventArgs e) { StreamReader sr = null; try { lvwData.Items.Clear(); //Limpa o conteúdo da ListView sr = new StreamReader(lblFile.Text); //Abre o arquivo //Monta a regular expression. StringBuilder é mais performático StringBuilder sbRegex = new StringBuilder(); sbRegex.Append(@"(?<date>(\d|\/)+)\s"); sbRegex.Append(@"(?<time>(\d|\:)+)\s"); sbRegex.Append(@"(?<user>(\S+))\s"); sbRegex.Append(@"(?<ip>(\d|\.)+)\s"); sbRegex.Append(@"(?<ws>(\w+\.\w+)+)\s");

Page 13: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

sbRegex.Append(@"(?<status>(\d{3}))"); //Cria o objeto que processará a regular expression Regex r = new Regex(sbRegex.ToString(), RegexOptions.IgnoreCase); string s; while((s = sr.ReadLine()) != null) //Lê linha a linha do arquivo texto { Match m = r.Match(s); if(m.Length != 0) //Verifica se corresponde a regular expression {

string[] sItens = new String[] //Monta um array com os valores { m.Groups["date"].Value, //Data m.Groups["time"].Value, //Tempo m.Groups["user"].Value, //Usuário m.Groups["ip"].Value, //IP m.Groups["ws"].Value, //Web Service m.Groups["status"].Value //Status }; ListViewItem item = new ListViewItem(sItens); //Cria um item lvwData.Items.Add(item); //Adiciona o item criado no ListView }

} } finally { if(sr != null) sr.Close(); //Fecha o arquivo } }}

Figura 3: Execução do formulário de log

Com estes recursos existe a possibilidade de escrever programas, não complicados e de baixa manutenção na atualização de funcionalidades, onde se faz traduções de layout, obtém-se arquivos em formatos proprietários e extraídos de sistemas legados, mainframe ou ERPs e os transformam, ou até mesmo escrever programas intermediários os quais façam interface entre sistemas diversos. Na maioria dos casos, as atualizações destes programas consistem na renovação da regular expression, e nas alterações dos “loops”. O interessante é que para manipular estas strings o modelo empregado na programação passa a ser orientado a objetos. Por exemplo, através de manipulações das coleções e não

Page 14: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

mais orientado ao layout, onde uma mudança é requerida do programa há necessidade de ser adaptado.

Transformação de Dados

Em XML existe o XSLT, cuja é uma linguagem de transformação de documentos. Com regular expression e as classes do Framework o comportamento de transformação de dados também possui característica própria.

O código abaixo utiliza o arquivo de log do exemplo anterior, e executa uma conversão para um novo documento XML, ou seja, transforma um arquivo plano para um arquivo XML, conforme figura 4.

//jsc /r:System.dll /r:System.Xml.dll /out:regexTransf.exe regexTransform.js

import System;import System.Text;import System.Text.RegularExpressions;import System.IO;import System.Xml;

//Abre o arquivo para leituravar sr:StreamReader = new StreamReader("c:\\samples\\regexlog.txt");//Abre o arquivo para gravaçãovar xml:XmlTextWriter = new XmlTextWriter("c:\\samples\\regexlog.xml", Encoding.Unicode);

xml.Formatting = Formatting.Indented; xml.WriteStartDocument(); //Inicializa o documento XMLxml.WriteStartElement("Log"); //Elemento raíz

//Monta a regular expression. StringBuilder é mais performático neste casovar sbRegex:StringBuilder = new StringBuilder();sbRegex.Append("(?<date>(\\d|\\/)+)\\s");sbRegex.Append("(?<time>(\\d|\\:)+)\\s");sbRegex.Append("(?<user>(\\S+))\\s");sbRegex.Append("(?<ip>(\\d|\\.)+)\\s");sbRegex.Append("(?<ws>(\\w+\\.\\w+)+)\\s");sbRegex.Append("(?<status>(\\d{3}))");

//Cria o objeto que processará a regular expressionvar r:Regex = new Regex(sbRegex.ToString(), RegexOptions.IgnoreCase);var s:String;var count:Int32;

//Lê linha a linha do arquivo textowhile((s = sr.ReadLine()) != null) { var m:Match = r.Match(s); if(m.Success) //Verifica se a linha lida corresponde a regular expression { xml.WriteStartElement("Linha"); //Abre o elemento Linha //Cria o atributo xml.WriteAttributeString("Posição", Convert.ToString(++count)); //Cria o elemento Data xml.WriteElementString("Data", m.Groups["date"].Value); //Cria o elemento Tempo xml.WriteElementString("Tempo", m.Groups["time"].Value);

Page 15: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

//Cria o elemento Usuário xml.WriteElementString("Usuário", m.Groups["user"].Value); //Cria o elemento IP xml.WriteElementString("IP", m.Groups["ip"].Value); //Cria o elemento WebService xml.WriteElementString("WebService", m.Groups["ws"].Value); //Cria o elemento Status xml.WriteElementString("Status", m.Groups["status"].Value); xml.WriteEndElement(); //Fecha o elemento Linha } }

sr.Close(); //Fecha o arquivo texto

xml.WriteEndElement(); //Fecha o elemento raízxml.WriteEndDocument(); //Finaliza com os dados do documento

//Fecha e grava o arquivo xmlxml.Flush();xml.Close();

Figura 4: Resultado da transformação de um arquivo plano para XML

Compilação

Como abordado anteriormente, um programa é gerado on-the-fly e executa o processamento do texto contra a regular expression. No entanto, quando se roda a aplicação,caso não estiver na memória, deverá ser criado(MSIL) e após isto compilado just-in-time. Porém, o que a classe Regex oferece é uma forma de persistir um ou mais regular expressions através do método estático CompileToAssembly. Este, por sua vez, cria um assembly com uma ou mais classes dedicadas a análises específicas,

Page 16: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

simplificando o modelo de programação e assim passa-se pela fase de geração do código MSIL, isto é, um grande beneficio na reutilização de código.

O exemplo abaixo produz um assembly para uma regular expression. A classe RegExCompilationInfo, passada através de um array, fornece as informações da classe onde é gerada, tais como flags, nome, namespace e, principalmente, a expressão elas passam através do construtor de RegExCompilationInfo. A outra classe é a AssemblyName a qual necessita apenas do nome do assembly cujo será produzido.

//cl regexCompile.cpp /CLR

#using <mscorlib.dll>#using <System.dll>

using namespace System;using namespace System::Text::RegularExpressions;using namespace System::Reflection;

void main() { //Define a regular expression String* p = new String("\\d{1,2}(\\/|\\-)\\d{1,2}(\\1)\\d{4}"); //Define os flags de opção, abaixo apenas caso insensitivo RegexOptions ro = RegexOptions::IgnoreCase; //Nome da classe String* n = new String("DateRegex"); //Namespace da classe String* ns = new String("MyNamespace");

//Assembly AssemblyName* a = new AssemblyName(); //Define o nome do assembly a->Name = "dateregexasm";

//Cria um array com 1 elemento com as informações do Regex para compilação RegexCompilationInfo* rc[] = { new RegexCompilationInfo(p, ro, n, ns, true)};

//Gera e persiste o assembly Regex::CompileToAssembly(rc, a);

}

O assembly produzido, na versão 0:0:0:0, pode ser inspecionado com o ILDASM. Verificando o MSIL, nota-se que classe privada RegexRunnerFactory é usada no construtor, conforme figura 5. O código a seguir faz uso do assembly produzido: //csc regexConsume.cs /r:dateregexasm.dll

using System;using System.Text.RegularExpressions;

class regexConsume{ static void Main() { //Instância a classe com padrão já determinado MyNamespace.DateRegex r = new MyNamespace.DateRegex();

Page 17: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

//Valor para ser testado string s = @"12/10/1990 12345-000 12-11-2000 34.123.123-1 12/12-2002"; //Percorre os valores correspondentes a regular expression for(Match m = r.Match(s); m.Success; m = m.NextMatch()) { Console.WriteLine(m.Value); //exibe no console } }}

Figura 5: Inspecionando o assembly produzido para manipulação da regular expression

RegularExpressionValidator

Em ASP.NET também pode ser usado o poder da regular expression. Nos controles de validação do Web Forms é encontrado o RegularExpressionValidator. A figura 6 ilustra o controle na caixa de ferramentas e também um exemplo para sua utilização. Para utilizá-lo, crie um projeto ASP.NET Web Application em Visual Basic.NET. Coloque no Web Form os controles da figura 6 (desenho a esquerda). Renomei a caixa de texto para txtName e o RegularExpressionValidator para regexVal. No controle regexVal, selecione a propriedade ControlToValidade para txtName e indique na propriedade ValidationExpression a expressão desejada(figura 7). Na propriedade ErrorMessage de regexVal coloque uma mensagem para ser exibida quando o padrão não ser o correspondido. No evento Click do botão de comando Validar, coloque o código abaixo:

Page 18: A Microsoft mostrou em Junho de 2000, durante o ...download.microsoft.com/download/f/d/4/fd4079d7-f96e-4cdb-859…  · Web viewNos casos gerais recomenda-se somente atualizar a regular

Regular Expressionpor Fabio R. Galuppo

lblResultado.Text = "Nome Validado!"

O resultados dos processamentos, válido e inválido, são mostrados na figura 8.

Figura 6: Detalhe do controle (a direita) e de uma parte do Web Form (a esquerda)

Figura 7: Montando a regular expression para a propriedade ValidationExpression

Figura 8: Resultado dos processamentos da regular expression