<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SubMundo Java &#187; regex</title>
	<atom:link href="http://submundojava.com.br/wordpress/category/regex/feed/" rel="self" type="application/rss+xml" />
	<link>http://submundojava.com.br/wordpress</link>
	<description>Um pouco de tudo, mas tecnologia acima de tudo!</description>
	<lastBuildDate>Wed, 26 May 2010 15:00:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Fluent Regex Composer</title>
		<link>http://submundojava.com.br/wordpress/2009/07/26/fluent-regex-composer/</link>
		<comments>http://submundojava.com.br/wordpress/2009/07/26/fluent-regex-composer/#comments</comments>
		<pubDate>Sun, 26 Jul 2009 20:32:47 +0000</pubDate>
		<dc:creator>Henrique Lima</dc:creator>
				<category><![CDATA[domain driven design]]></category>
		<category><![CDATA[fluent interface]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://submundojava.com.br/wordpress/?p=30</guid>
		<description><![CDATA[Na semana passada, Martin Fowler escreveu um artigo demonstrando as práticas que ele costuma utilizar ao trabalhar com expressões regulares. Neste artigo, o senhor Fowler propõe uma maneira de separar uma expressão regular em partes menores, recompondo tal expressão posteriormente para, entre outra coisas, dar maior legibilidade ao código. Ao acabar de ler o artigo [...]]]></description>
			<content:encoded><![CDATA[<p>Na semana passada, <a title="Martin Fowler" href="http://www.martinfowler.com/" target="_blank">Martin Fowler</a> escreveu um <a title="artigo" href="http://martinfowler.com/bliki/ComposedRegex.html" target="_blank">artigo</a> demonstrando as práticas que ele costuma utilizar ao trabalhar com expressões regulares. Neste artigo, o senhor Fowler propõe uma maneira de separar uma expressão regular em partes menores, recompondo tal expressão posteriormente para, entre outra coisas, dar maior legibilidade ao código. Ao acabar de ler o <a title="artigo" href="http://martinfowler.com/bliki/ComposedRegex.html" target="_blank">artigo</a> a primeira coisa que veio em minha cabeça foi <a title="Fluent Interface" href="http://en.wikipedia.org/wiki/Fluent_interface" target="_blank">Fluent Interfaces</a>. Na atualização de seu <a title="artigo" href="http://martinfowler.com/bliki/ComposedRegex.html" target="_blank">artigo</a>, Martin Fowler cita este assunto (inclusive expôe sua preferência por não utilizar <a title="Fluent Interfaces" href="http://en.wikipedia.org/wiki/Fluent_interface" target="_blank">Fluent Interfaces</a>) e sugere uma <a title="alternativa fluente" href="http://flimflan.com/blog/ReadableRegularExpressions.aspx" target="_blank">alternativa fluente</a> criada por <a title="Joshua Flanagan" href="http://flimflan.com/blog/default.aspx" target="_blank">Joshua Flanagan</a> para C#.</p>
<p>Este post não tem como  objetivo discutir se utilizar <a title="Fluent Interfaces" href="http://en.wikipedia.org/wiki/Fluent_interface" target="_blank">Fluent Interfaces</a>, ou não, é a melhor maneira de resolver problemas relacionados a expressões regulares, mas sim, propor um exercício a fim de criar uma <strong>possível</strong> API fluente e, ao final do artigo, demonstrar uma pequena porção de código Java que pode solucionar alguns problemas relacionados a expressões regulares utilizando esta abordagem.</p>
<p><strong>O problema</strong></p>
<p>O grande problema de quando trabalhamos com expressões regulares é conhecer todos os recursos disponíveis (metacaracteres, quantificadores gananciosos, possessivos, relutantes, etc) para validarmos determinada String e posteriormente recuperarmos os grupos que nos interessa para aplicarmos a lógica que necessitamos. Além disso, quanto maior for a expressão mais difícil será de interpretá-la, por isso, utilizar a abordagem &#8220;<a title="Divisão e Conquista" href="http://pt.wikipedia.org/wiki/Divis%C3%A3o_e_conquista" target="_blank">Divisão e Conquista</a>&#8221; é uma boa prática a ser seguida.</p>
<p><strong>A solução</strong></p>
<p>Criar uma API para abstrair os recursos (metacaracteres, quantificadores, etc) e disponibilizar ao usuário, métodos mais legíveis e simples de escrever. Para chegar a este fim, me propus a analisar as expressões regulares que mais utilizo no dia-a-dia, &#8220;mapeá-las&#8221; para o português estruturado e, então, escrever uma porção de código que reflita a interpretação do português estruturado o mais fluente possível.</p>
<p><strong>Interpretando Expressões Regulares</strong></p>
<p>Analisando uma expressão regular que tem como objetivo validar se Strings representam uma data em um formato dd/mm/aaaa (em java dd/MM/yyyy), temos:</p>
<p><strong>Expressão Regular:</strong> \\d{2}/\\d{2}/\\d{4}</p>
<p><strong>Português estruturado:</strong> A String em questão: Inicia com dois dígitos (numéricos), seguido de uma barra, seguido de dois dígitos (numéricos), seguido de uma barra e finaliza com quatro dígitos (númericos).</p>
<p><strong>Código Java:</strong></p>
<pre class="prettyprint">RegexComposer composer = RegexComposer.getInstance();
composer
    .startsWith(exactly(2, digit()))
    .followedBy(exactly(1, literal("/")))
    .followedBy(exactly(2, digit()))
    .followedBy(exactly(1, literal("/")))
    .finishedWith(exactly(4, digit()));</pre>
<p>Parece bacana, mas não está ao contrário? Porque o quantificador vem antes do dígito no código Java e na expressão regular não? Pois ao interpretarmos a expressão regular em português estruturado, também passamos o quantificador a frente do dígito e é essa a diferença, pois, ao interpretarmos uma expressão como: \\d{2} nós não escrevemos &#8220;Esta expressão representa digítos (numéricos) <strong>dois</strong>&#8220;, e sim &#8220;Esta expressão representa <strong>dois</strong> dígitos (numéricos)&#8221;.</p>
<p>Este foi o meu principal questionamento quando analisei a <a title="API" href="http://flimflan.com/blog/ReadableRegularExpressions.aspx" target="_blank">API</a> do senhor <a title="Joshua Flanagan" href="http://flimflan.com/blog/default.aspx" target="_blank">Joshua Flanagan</a>, pois acredito que ao utilizarmos a abordagem fluente, devemos valorizar a maneira  como escreveríamos em uma língua (português/inglês) e não como é a sintaxe de uma determinada linguagem (de programação).</p>
<p><strong>Delimitadores</strong></p>
<p>Uma ocorrência constante (inclusive citado no <a title="artigo" href="http://martinfowler.com/bliki/ComposedRegex.html" target="_blank">artigo</a> do <a title="Martin Fowler" href="http://www.martinfowler.com/" target="_blank">Martin Fowler</a>) é a utilização de delimitadores para separarmos os dados em Strings (tokens). São exemplos disto, os arquivos CSV (valores separados por vírgula) e também a data do exemplo anterior (separados por barra &#8220;/&#8221;). Desta forma, seria conveniente se pudessemos configurar a API para interpretar delimitadores. A seguir, demostro um exemplo de como isto poderia ser feito:</p>
<p><strong>Expressão Regular:</strong> \\d{2}/\\d{2}/\\d{4}</p>
<p><strong>Português estruturado:</strong> A String em questão: Inicia com dois dígitos (numéricos), seguido de dois dígitos (numéricos), finaliza com quatro dígitos (númericos) e é delimitada por uma barra.</p>
<p><strong>Código Java:</strong></p>
<pre class="prettyprint">RegexComposer composer = RegexComposer.getInstance();
composer
    .startsWith(exactly(2, digit()))
    .followedBy(exactly(2, digit()))
    .finishedWith(exactly(4, digit()))
    .delimitedBy(exactly(1, literal("/")));</pre>
<p>Tá começando a melhorar, mas existe um recurso muito importante que deve ser considerado, os agrupamentos.</p>
<p><strong>Agrupamentos</strong></p>
<p>Os agrupamentos em Java são efetuados através inserção da expressão em parênteses, isto possibilita recuperar a String de determinado grupo uma vez que foi validado que a String se encontra no padrão requerido. A seguir demonstro uma maneira que, inicialmente, acreditei ser adequada para este fim.</p>
<p>Imagine que, após validar uma determinada data, você queira recuperar o dia, mês e ano separadamente para efetuar alguma lógica, então, teríamos algo como:</p>
<p><strong>Expressão Regular: </strong>(\\d{2})/(\\d{2})/(\\d{4})</p>
<p><strong>Português estruturado:</strong> A String em questão: Inicia com dois dígitos (numéricos) <strong>agrupados</strong>, seguido de dois dígitos (numéricos) <strong>agrupados</strong>, finaliza com quatro dígitos (númericos) <strong>agrupados</strong> e é delimitada por uma barra.</p>
<p><strong>Código Java:</strong></p>
<pre class="prettyprint">RegexComposer composer = RegexComposer.getInstance();

Pattern p = composer
                 .startsWith(exactly(2, digit()).<strong>grouped()</strong>)
                 .followedBy(exactly(2, digit())<strong>.grouped()</strong>)
                 .finishedWith(exactly(4, digit())<strong>.grouped()</strong>)
                 .delimitedBy(exactly(1, literal("/")))
                 .compile();

Matcher matcher = p.matcher("05/01/1979");

if(matcher.matches()) {

    System.out.println("Dia: " + matcher.group(1));
    System.out.println("Mes: " + matcher.group(2));
    System.out.println("Ano: " + matcher.group(3));

} else {

     System.out.println("Formato invalido");

}</pre>
<p>Legal, ao menos à primeira vista, entretanto eu ainda precisaria saber em qual grupo está o dia (matcher.group(1)), o mês (matcher.group(2)) e o ano (matcher.group(3)) e isto não é muito bacana. Creio que o ideal seria criarmos um alias para cada grupo e depois recuperarmos o número do grupo através do alias. Seria algo como <strong>.startsWith(exactly(2, digit()).grouped(usingAlias(&#8221;dia&#8221;)))</strong> e depois recuperarmos o grupo usando <strong>matcher.group(composer.getAliasGroup(&#8221;dia&#8221;))</strong>. Uma outra questão é que há outra interpretação para expressões agrupadas, por exemplo, &#8220;A String em questão: Inicia com<strong> um grupo</strong> de dois dígitos &#8230;&#8221;. Isto quer dizer que escreveriamos algo como: <strong>.startsWith(groupOf(exactly(2, digit())).usingAlias(&#8221;dia&#8221;))</strong>.</p>
<p>Embora eu considere estas opções adequadas, não escrevi nada disso ainda. No exemplo, a seguir, irei demonstrar um pouco mais de detalhes do que já implementei.</p>
<p><strong>Exemplo prático</strong></p>
<p>Utilizando o exemplo que o <a title="Martin Fowler" href="http://www.martinfowler.com/" target="_blank">Martin Fowler</a> deu em seu <a title="artigo" href="http://martinfowler.com/bliki/ComposedRegex.html" target="_blank">artigo</a>, irei validar se a String <strong>&#8220;score 400 for 2 nights at Minas Tirith Airport&#8221;</strong> se encontra no padrão correto e ,após isto, recuperar os números 400 e 2.</p>
<p><strong>Código Java:</strong></p>
<pre class="prettyprint">import br.com.submundojava.regexcomposer.RegexComposer;
import static br.com.submundojava.regexcomposer.quantifier.Quantifiers.*;
import static br.com.submundojava.regexcomposer.value.MetaCharacters.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 *
 * @author Henrique Lima
 */
public class Test {

    public static void main(String argz[]) {

        RegexComposer composer = RegexComposer.getInstance();

        Pattern pattern = composer
                        .startsWith(exactly(1, literal("score")))
                        .followedBy(oneOrMore(digit()).grouped())
                        .followedBy(exactly(1, literal("for")))
                        .followedBy(oneOrMore(digit()).grouped())
                        .followedBy(exactly(1, literal("night")))
                        .followedBy(zeroOrOne(literal("s")))
                        .followedBy(exactly(1, literal("at")))
                        .delimitedBy(zeroOrMore(whiteSpace()))
                        .finishedWith(oneOrMore(any()))
                        .compile();

        Matcher matcher = pattern.matcher("score 400 for 2 nights at Minas Tirith Airport");

        if (matcher.matches()) {

            System.out.println(matcher.group(1));
            System.out.println(matcher.group(2));

        } else {
            System.out.println("Formato inválido");
        }

    }

}</pre>
<p>Muito simples! Veja que não utilizamos nenhum metacaracter, nenhum quantificador, agrupamos os dados necessários e ainda utilizamos um delimitador. Uma pessoa nem precisaria conhecer de expressões regulares para validar a String (embora seja desejável).</p>
<p>Perceba que novas coisas aconteceram e utilizamos <strong>import static</strong> do Java 5 para disponibilizarmos os métodos necessários à nossa classe. Além disso, utilizamos novos métodos quantificadores (não regex) que são: <strong>zeroOrMore</strong>(), para zero ou mais ocorrências (análogo a *), <strong>oneOrMore</strong>(), para uma ou mais ocorrências (análogo a +), <strong>zeroOrOne</strong>() para zero ou uma ocorrência (análogo a ?) e por final utilizamos o método <strong>compile()</strong> para obtermos um objeto do tipo <strong>java.util.regex.Pattern</strong> para podermos validar a String.</p>
<p><strong>Código fonte</strong></p>
<p>Abaixo segue o projeto que criei para efetuar este post.</p>
<p>Para netbeans: <a title="download" href="http://www.submundojava.com.br/henrique/regular-expression-composer-netbeans.zip" target="_blank">download</a><br />
Para eclipse: <a title="download" href="http://www.submundojava.com.br/henrique/regular-expression-composer-eclipse.zip" target="_blank">download</a></p>
<p><strong>Considerações Finais</strong></p>
<p>Procurei demonstrar uma maneira fluente de trabalhar com expressões regulares, abstraindo seus recursos e disponibilizando métodos de alto nível. O exemplo que escrevi ainda está muito &#8220;verde&#8221;, com nomes esquisitos para algumas classes, métodos e pacotes. Na verdade, em alguns casos, nem sei se o inglês está correto.</p>
<p>Além disso, existem muitas limitações, por exemplo, se eu quiser usar um delimitador e ao mesmo tempo validar um dos tokens com um outro RegexComposer, não é possível. Seria desejável poder aninhar RegexComposer&#8217;s para este fim. Outro detalhe é que os métodos da classe RegexComposer recebem sempre uma instância de Quantifier e deveriam receber uma instância de uma classe com um nome mais adequado, como Expression ou ExpressionGroup. Detalhes a serem resolvidos.</p>
<p>Aguardo seus comentários e quem quiser entrar em contato, meu twitter é <a title="hgflima" href="http://twitter.com/hgflima" target="_blank">hgflima</a></p>
<p>Um abraço.</p>
]]></content:encoded>
			<wfw:commentRss>http://submundojava.com.br/wordpress/2009/07/26/fluent-regex-composer/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
