Expressões Regulares

Expressões regulares, embora críticas, são uma poderosa ferramenta para trabalhar com texto. O Ruby possui esta funcionalidade incluída em seu núcleo. Elas são usadas para o casamento de padrões e processamento de texto.

Muitas pessoas acham que expressões regulares são difíceis de usar, difíceis de ler, de manter e, consequentemente, improdutivas. Você pode acabar usando apenas um pequeno número de expressões regulares em suas aplicações em Ruby e Rails. Não é pré-requisito, para programar em Rails, tornar-se um especialista em Expressões Regulares. Entretanto, é recomendado o aprendizado, ao menos o básico de como as expressões regulares funcionam.

Uma expressão regular é uma forma simples de especificar um padrão de caracteres que será casado com uma string. Em Ruby, você normalmente cria uma expressão regular escrevendo um padrão entre caracteres de barra ‘/’ (/padrão/). Em Ruby, expressões regulares são objetos (do tipo Regexp) e podem ser manipulados como tais. // é uma expressão regular e uma instância da classe Regexp, como demonstrado abaixo:

1 //.class    # Regexp

Você pode escrever um padrão que casa com uma cadeia de caracteres contendo o texto Pune ou o texto Ruby usando a seguinte expressão regular:

1 /Pune|Ruby/

Caracteres de barra (‘/’) delimitam o padrão, que consistem em dois padrões que serão casados, separados por um caractere de pipe (|). O caractere pipe (|) significa “ou o padrão que está a direita ou o padrão que está a esquerda”, neste caso Pune ou Ruby.

A forma mais simples de verificar se há um padrão que case entre uma expressão regular e uma cadeia de caracteres é o método match/. Você pode fazer isso em qualquer direção: objetos Regexp e objetos String, ambos respondem ao método match. Se não houver casamento entre os padrões, o método retorna nil. Se houver um casamento de padrão, é retornado uma instância da classe MatchData. Podemos utilizar o operador =~ para casar uma cadeia de caracteres contra uma expressão regular. Caso o padrão seja encontrado, =~ retorna a posição em que o padrão foi encontrado, caso contrário retorna nil.

1 m1 = /Ruby/.match("O futuro eh Ruby")
2 puts m1.class  # retorna MatchData
3 m2 = "O futuro eh Ruby" =~ /Ruby/
4 puts m2          # retorna 14

Os possíveis componentes de uma expressão regular incluem os seguintes:

Caracteres literais

Qualquer caractere literal que for adicionado em uma expressão regular casa consigo mesmo na string.

1 /a/

Esta expressão regular casa com a cadeia de caracteres “a”, assim como qualquer cadeia de caracteres que contenha a letra “a”.

Alguns caracteres têm significado especial para o parser de expressões regulares. Quando você quer casar algum desses caracteres especiais, você tem que escapá-lo com o caractere de barra-invertida (\). Por exemplo, para casar o caractere ? (interrogação), você deve escrever isto:

1 /\?/

A barra-invertida significa “não considere o próximo caractere como especial, trate-o como ele mesmo.”

Os caracteres especiais incluem ^, $, ? , ., /, \, [, ], {, }, (, ), +, e *.

O caractere coringa . (ponto)

Algumas vezes você irá querer casar qualquer caractere em algum ponto do seu padrão. Isto é feito utilizando o caractere coringa . (ponto). Um ponto casa com qualquer caractere exceto o caractere de nova linha (\n). Esta expressão regular:

1 /.ejected/

casa, ao mesmo tempo, com “dejected” e “rejected”. Também casa com “%ejected” e “8jected”. O caractere coringa é muito útil, mas algumas vezes ele casa com mais padrões do que o desejado. Entretanto, você pode impor condições no casamento de padrões enquanto permite o casamento de múltiplas cadeias de caracteres, usando classes de caracteres.

Classes de Caracteres

Uma classe de caractere é uma lista explicita de caracteres, colocada entre colchetes em uma expressão regular:

1 /[dr]ejected/

Isto significa “case d ou r, seguido de ejected”. Este novo padrão casa tanto com “dejected” ou “rejected”, mas não com “&ejected”. Uma classe de caracteres é um tipo de caractere quase coringa: elas possibilitam múltiplos caracteres em uma posição na expressão regular, mas apenas um número limitado de caracteres.

Em uma classe de caracteres, você pode, inclusive, incluir um intervalo de caracteres. Um uso comum desses intervalos é a classe para letras minúsculas:

1 /[a-z]/

Para casar um dígito hexadecimal, você pode usar mais de um intervalo em uma classe de caracteres:

1 /[A-Fa-f0-9]/

Esta classe casa com qualquer caractere de a à f (maiúsculo ou minúsculo) ou qualquer dígito.

Algumas vezes você precisa casar qualquer caratere exceto aqueles que estão em uma lista especial. Você pode, por exemplo, verificar se o primeiro caractere em uma string não é um dígito hexadecimal válido.

Você cria esse tipo de “busca negativa” negando uma classe de caracteres. Para fazer isso, você coloca um caractere de acento circunflexo (^) no comeco da classe. Aqui está a classe que casa com qualquer caractere exceto aqueles que são digitos hexadecimais válidos:

1 /[^A-Fa-f0-9]/

Algumas classes de caracteres são tão comuns que possuem abreviações especiais.

Sequencias especiais de escape para classes de caracteres comuns

Para casar qualquer digito você pode fazer assim:

1 /[0-9]/

Mas você pode fazer a mesma coisa de forma mais concisa com a sequência especial de escape \d:

1 /\d/

Outras duas sequencias de escape predefinidas bastante úteis são:
\w que casa qualquer dígito, caractere alfabético ou caractere de underscore (_).
\s que casa qualquer caractere de espaço em branco (espaço, tabulação, linha nova).

Cada uma dessas classes predefinidas possui sua forma negada. Você pode casar qualquer caractere que não seja um dígito fazendo isto:

1 /\D/

Da mesma forma, \W casa com qualquer caractere que não seja alfabético ou underscore, e \S casa com qualquer caractere que não seja espaço em branco.

Sempre que um padrão casa um objeto MatchData é retornado.

Toda operação de casamento pode ser bem sucedida ou falhar. Vamos iniciar pelo caso mais simples: a falha. Quando você tentar casar uma string com um padrão, e não houver casamento, o resultado é sempre nil:

1 /a/.match("b") # nil

Este nil funciona como falso ou “sem resposta” quando um casamento de padrão é tratado como um teste verdadeiro/falso.

Diferentemente de nil, um objeto MatchData retornado por um casamento bem sucedido é tratado como um valor Booleano verdadeiro, que torna simples os teste de casamento/não casamento. Além disso, o objeto MatchData retornado armazena os dados do casamento, possibilitando que você possa verificá-los com os métodos apropriados: onde o casamento iniciou (em qual caractere na string), quanto do padrão casou na string, o que foi capturado nos agrupamentos entre parênteses, e outras coisas mais.

Para utilizar o objeto MatchData, você precisa, primeiramente, armazená-lo. Considere um exemplo em que gostaríamos de extrair um número de telefone de uma string e armazenar suas diferentes partes (código de área, operadora, número) em partes. Exemplo p064regexp.rb

 1 # p064regexp.rb
 2 string = "Meu telefone é (123) 555-1234."
 3 phone_re = /\((\d{3})\)\s+(\d{3})-(\d{4})/
 4 m = phone_re.match(string)
 5 unless m
 6   puts "Não houve casamento..."
 7   exit
 8 end
 9 print "Toda a string com que começamos: "
10 puts m.string
11 print "Toda a parte da string que foi casada: "
12 puts m[0]
13 puts "As três capturas: "
14 3.times do |index|
15   puts "Captura ##{index + 1}: #{m.captures[index]}"
16 end
17 puts "Outro jeito de conseguir a primeira captura:"
18 print "Captura #1: "
19 puts m[1]

Neste código, nós usamos o método string do objeto MatchData (puts m.string) para obter toda string em que a operação match foi executada. Para obter as partes da string que casaram com nosso padrão, nós adicionamos os índices do objeto MatchData entre colchetes, com o valor 0 no índice. Também usamos o método times (3.times do |index|) para iterar exatamente 3 vezes com o bloco de código e imprimir os subcasamentos (as capturas entre parenteses) sucessivamente. Dentro do bloco de código o método chamado captures extrai as substrings que casam com a parte do padrão que está entre parênteses. Finalizando, nós exibimos novamente a primeira captura, mas dessa vez utilizamos uma técnica diferente: indexamos o objeto MatchData diretamente com colchetes e inteiros positivos, cada inteiro correspondendo a uma captura.

Aqui está a saída:

 1 >ruby p064regexp.rb
 2 Toda a string com que começamos: Meu telefone é (123) 555-1234.
 3 Toda a parte da string que foi casada (123) 555-1234
 4 As três capturas:
 5 Captura #1: 123
 6 Captura #2: 555
 7 Captura #3: 1234
 8 Outro jeito de conseguir a primeira captura:
 9 Capture #1: 123
10 >Exit code: 0

Leia o tutorial de expressões regulares do site Regular-Expressions.info, para mais detalhes quanto à expressões regulares na linguagem Ruby.

Uma boa aplicação para testar suas expressões regulares é o Rubular.com.

O tópico acima foi adaptado do livro Ruby for Rails.

Logo do Guru-SP

Este material tem como base o tutorial do RubyLearning.com de Satish Talim e foi traduzido por membros do GURU-SP com a permissão do autor.

Ajude o RubyLearning participando em algum dos cursos pagos ou fazendo uma doação para o projeto

Voltar para o índice