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

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"

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)

"foo+account2@gmail.com"[/\+([^@]+)/, 1] # matches capture group 1, i.e. what is inside ()
# => "account2"
"foo+account2@gmail.com"[/\+([^@]+)/]    # matches capture group 0, i.e. the whole match
# => "+account2"

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

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 ).


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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.