Encontrando um padrão, não uma string exata
"Isso parece um email?" é outra pergunta que "isso é aquela string?"
input = "[email protected]"
input == "[email protected]" # true, mas só para esse endereço exato
Essa comparação responde a uma pergunta sobre uma string específica. Um formulário de cadastro não sabe de antemão o email de quem visita. Ele precisa checar "isso parece um email": uma forma, e não um valor exato. O == não consegue dizer "alguns caracteres, depois um @, depois mais caracteres, depois um ponto, depois algumas letras". Uma expressão regular (regex, para encurtar) consegue.
Um literal de regex, escrito em Ruby
pattern = /gmail/
pattern.class
# Regexp
/gmail/ é um objeto Regexp, um objeto Ruby como qualquer outro, criado com barras em vez de Regexp.new. O regex mais simples é texto puro. /gmail/ casa com qualquer string que tenha os caracteres g, m, a, i, l nessa ordem, em qualquer ponto dela.
=~: o primeiro jeito de rodar um
"[email protected]" =~ /gmail/
# 4, o índice onde o match começa
"[email protected]" =~ /gmail/
# nil, nenhum match em lugar nenhum da string
O =~ roda o regex contra uma string e devolve o índice onde começa o primeiro match, ou nil se nada casar. nil é falsy e todo inteiro (inclusive 0) é truthy, então o =~ cabe direto num if:
email = "[email protected]"
if email =~ /gmail/
puts "parece um endereço do Gmail"
end
# "parece um endereço do Gmail"
Cuidado com uma ponta afiada. Um match no índice 0 continua sendo match, e 0 é truthy em Ruby (só nil e false são falsy), então esse padrão é seguro. Ele quebraria com um método que devolvesse false quando não há match, em vez de nil. Por isso o contrato "índice ou nil" do =~ importa.
Nem todo caractere significa ele mesmo
., *, +, ?, [, ], (, ), {, }, |, \, ^ e $ têm significados especiais dentro de um regex. Este curso trata de vários deles a partir da aula 5. Por enquanto: para casar um desses caracteres como texto comum, escape-o com uma barra invertida:
"3.14" =~ /3.14/ # 0, mas "." aqui significa "qualquer caractere", então isso também dá match com "3x14"
"3x14" =~ /3.14/ # 0, deu match mesmo assim, provavelmente não era a intenção
"3.14" =~ /3\.14/ # 0, "\." significa um ponto literal, e só um ponto literal
"3x14" =~ /3\.14/ # nil, corretamente rejeitado
Para onde isso vai
Este curso monta o kit por trás daquela checagem de email. Ele cobre como tirar pedaços estruturados de um match, como achar toda ocorrência em vez da primeira e as âncoras e classes de caracteres que impedem um padrão de ficar frouxo demais. Depois vem busca e substituição. A última aula usa tudo isso para ler uma expressão regular que roda nos models desta app.
Pontos-chave
==checa uma string exata; um regex checa uma forma que muitas strings diferentes podem ter./pattern/é um objetoRegexp; o=~o roda contra uma string e devolve o índice do primeiro match, ounilse não houver match.0é um índice de match válido e truthy em Ruby, entãoif str =~ /pattern/trata "casou no início" como match.- Caracteres como
.,*,+e?são especiais dentro de um regex; para casar um deles como texto comum, escape:\.em vez de..
Continue com a aula 2
MatchData ou um simples Sim/Não: match vs match?
Compara o match, que devolve MatchData, com o match?, que devolve um booleano e não mexe em $~.
Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.