Utilizando Expressões Regulares em Ruby

16 Apr 2011 . category: article . Comments
#ruby #regex

Não poderia começar este post sem citar o livro do Aurelio, Expressões Regulares - Uma Abordatem Divertida. Um excelente livro. Valeu mesmo Aurélio, depois dele pude realmente afirmar: “Eu sei utilizar expressões regulares.”

O que eu quero passar neste post são algumas formas de se utilizar expressões regulares na linguagem de programação Ruby. Como dica também gostaria de deixar o site rubular.com, esta é uma ótima ferramenta para testar as regexes.

Criando uma Regex

Um objeto do tipo regex pode ser instanciado através da classe Regexp, passando a expressão como primeiro parâmetro. No segundo parâmetros são passados os modificadores concatenados em uma string

Regexp.new('expressao')
Regexp.new('expressao','im')

utilizando a seguinte syntax /expressao/

/expressao/
/expressao/im

ou utilizando a syntax %r{expressao}, esta forma permite criar a expressão em mais de uma linha.

%r{expressao}

São suportados os seguintes modificadores: i: ignora diferenças entre letras maiúsculas e minusculas(case insensitive); x: ignora quebras de linhas dentro da regex; m: ignora match em quebra de linhas; o: de uma forma simples de explicar, a regex é executada apenas um vez dentro de um bloco de comandos;

Operação de match

Os objetos do tipo Regexp possuem os método match e =~. A diferença entre os dois é o valor de retorno, o primeiro retorna um objeto do tipo MatchData enquanto que o segundo retorna um fixnum com a posição do primeiro carácter que bateu com a expressão regular.

Quando um match é executado alguns valores são atribuídos a variáveis especiais, facilitando a recuperação dos resultados. As variáveis são: $~: possui o mesmo conteúdo retornado pelo match; $n: retorna o retrovisor de valor n; $+: retorna o ultimo grupo capturado;

r = Regexp.new('teste')
= /teste/
r.match('TESTE')
= nil
r = Regexp.new('teste','i') #com parametro i
= /teste/i
r.match('TESTE')
= #<MatchData "TESTE">
file = $+ if /path/to/file.jpg =~ /\/([^\/]+)$/
puts file
= file.jpg

Operação de substituição

A classe String possui alguns métodos que são utilizados para realizar substituições: os métodos sub e sub!, que modifica apenas a primeira ocorrência e os método gsub e gsub! que modificam todas as ocorrências. A diferença entre o método que não contém e o que contém exclamação é que o valor de retorno é uma string modificada e o objeto que chamou o método não é modificado, enquanto que o segundo modifica seu próprio conteúdo. O sinal ‘!’ é um padrão em Ruby, quando ele está presente no nome do método significa que o conteúdo do objeto será alterado, mas é só um padrão, isso não é obrigatório.

Os retrovisores podem ser utilizados no gsub e sub e eles são chamados com ‘\n’, sendo n sua posição.

O primeiro parâmetro do método gsub é a expressão regular e o segundo aceita dois tipos valores: uma string contento o termo que será utilizado na substituição ou uma proc que será executado a cada match realizado.

'arquivo.txt'.sub(/\.\w+$/,'')
= 'arquivo'
n = 0
'pg, pg, pg'.gsub(/pg/) do
  n += 1
end
= '1, 2, 3'

Método Scan

Existe um método da classe String chamado scan. Esse método recebe como parametro uma regex e retorna um array de strings que casaram. Se houver grupos na regex um array de array de string será retornado.

O método também aceita um bloco de comandos como parametro. Esse bloco será executado recebendo cada elemento do array de retorno.

Um exemplo do uso do método scan.

"9999-9999 8888-8888".scan(/\d{4}-\d{4}/)
= ["9999-9999", "8888-8888"]

"9999-9999 8888-8888".scan(/(\d{4})-(\d{4})/)
= [["9999", "9999"], ["8888", "8888"]]

"9999-9999 8888-8888".scan(/(\d{4})-(\d{4})/) {|tel| puts tel.join(':')}
9999:9999
8888:8888
= "9999-9999 8888-8888"

Estou sem idéias para exemplos melhores, porém acredito que esses funcionam.

Observações

As expressões regulares em Ruby são implementadas utilizando como base a implementação do Perl, por isso o uso das mesmas nas duas linguagens são bem parecidas. Entendo bem como funciona em Ruby, fica fácil utiliza-los em Perl, mas existe algumas diferenças, como por exemplo o retorno do operador =~(que no caso por é retorna um string) e das substituições que podem ser escritas com a seguinte syntax:

s/expressao/string # no caso do sub
s/expressao/string/g # no caso de gsub

Se alguém quiser dar alguma contribuição, por favor, usem os comentários deste post.

[]’s


Me

Tenho estudado esse mundo mágico da programação desde 2005. Já consegui sustentar minha família usando Ruby, Java, Python, C++ e Javascript. O resto tenho usado para diversão ou aprendizado.