Retorne a primeira correspondência de Ruby regex

97

Estou procurando uma maneira de realizar uma correspondência de regex em uma string em Ruby e causar um curto-circuito na primeira correspondência.

A string que estou processando é longa e, pelo que parece, a maneira padrão ( matchmétodo) processaria tudo, coletaria cada correspondência e retornaria um objeto MatchData contendo todas as correspondências.

match = string.match(/regex/)[0].to_s
Daniel Beardsley
fonte

Respostas:

134

Você pode tentar variableName[/regular expression/]. Este é um exemplo de saída do irb:

irb(main):003:0> names = "erik kalle johan anders erik kalle johan anders"
=> "erik kalle johan anders erik kalle johan anders"
irb(main):004:0> names[/kalle/]
=> "kalle"
Presidente
fonte
Isso não está combinando e retornando o primeiro resultado nos bastidores?
Gishu
7
Após algum benchmarking com strings de vários comprimentos e olhando para a fonte C, descobriu-se que Regex.match causa curto-circuito e encontra apenas a primeira correspondência.
Daniel Beardsley
3
Legal, não sabia sobre este atalho.
Pierre
Existe alguma documentação sobre este atalho? Pesquisei de alto a baixo o que achei ser uma tarefa relativamente simples e só resolvi meu problema depois de encontrar isso. Obrigado!
dmourati
5
@dmourati Você pode encontrar esse recurso documentado em String # [] . Obrigado por perguntar sobre o documento, porque ao lê-lo encontrei o captureargumento - que permite retornar uma captura em vez da correspondência completa.
preguiça
68

Você pode usar []: (que é como match)

"[email protected]"[/\+([^@]+)/, 1] # matches capture group 1, i.e. what is inside ()
# => "account2"
"[email protected]"[/\+([^@]+)/]    # matches capture group 0, i.e. the whole match
# => "+account2"
Benjamin Crouzier
fonte
4
melhor resposta completa
akostadinov
23

Se apenas a existência de uma correspondência for importante, você pode ir com

/regexp/ =~ "string"

De qualquer forma, matchdeve retornar apenas o primeiro resultado, enquanto scanpesquisa em toda a string. Portanto se

matchData = "string string".match(/string/)
matchData[0]    # => "string"
matchData[1]    # => nil - it's the first capture group not a second match
Slartibartfast
fonte
8

Ainda não tenho certeza se esse recurso é incrível ou totalmente louco, mas sua regex pode definir variáveis ​​locais.

/\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ "$3.67" #=> 0
dollars #=> "3"

(Retirado de http://ruby-doc.org/core-2.1.1/Regexp.html ).

Felix
fonte
Recurso incrível! Exatamente o que eu precisava
RaphaMex
Advertência: só funciona quando regex =~ string", not when string = ~ regex`
Christopher Oezbek
2

Uma Expressão Regular (regex) nada mais é que uma máquina de estado finito (FSM).

Um FSM tenta responder à pergunta "Este estado é possível ou não?"

Ele continua tentando fazer uma correspondência de padrão até que uma correspondência seja encontrada (sucesso) ou até que todos os caminhos sejam explorados e nenhuma correspondência seja encontrada (falha).

Em caso de sucesso, a pergunta "Esse estado é possível ou não?" foi respondido com um "sim". Portanto, nenhuma correspondência adicional é necessária e a regex retorna.

Veja isso e isso para saber mais sobre isso.

Além disso: aqui está um exemplo interessante para demonstrar como funciona o regex. Aqui, uma regex é usada para detectar se um determinado número é primo. Este exemplo está em perl, mas também pode ser escrito em ruby.

Litmus
fonte