Existe uma maneira rápida de encontrar todas as correspondências de uma expressão regular no Ruby? Eu olhei através do objeto Regex no Ruby STL e procurei no Google sem sucesso.
Existe uma maneira rápida de encontrar todas as correspondências de uma expressão regular no Ruby? Eu olhei através do objeto Regex no Ruby STL e procurei no Google sem sucesso.
Respostas:
Usar scan
deve fazer o truque:
string.scan(/regex/)
/(?=(...))/
.
Para encontrar todas as seqüências correspondentes, use o scan
método String .
str = "A 54mpl3 string w1th 7 numb3rs scatter36 ar0und"
str.scan(/\d+/)
#=> ["54", "3", "1", "7", "3", "36", "0"]
Se você quiser, MatchData
que é o tipo do objeto retornado pelo match
método Regexp , use:
str.to_enum(:scan, /\d+/).map { Regexp.last_match }
#=> [#<MatchData "54">, #<MatchData "3">, #<MatchData "1">, #<MatchData "7">, #<MatchData "3">, #<MatchData "36">, #<MatchData "0">]
A vantagem de usar MatchData
é que você pode usar métodos como offset
:
match_datas = str.to_enum(:scan, /\d+/).map { Regexp.last_match }
match_datas[0].offset(0)
#=> [2, 4]
match_datas[1].offset(0)
#=> [7, 8]
Veja estas perguntas se quiser saber mais:
Lendo sobre variáveis especiais $&
, $'
, $1
, $2
em Ruby será útil também.
se você tiver uma regexp com grupos:
str="A 54mpl3 string w1th 7 numbers scatter3r ar0und"
re=/(\d+)[m-t]/
você pode usar o scan
método String para encontrar grupos correspondentes:
str.scan re
#> [["54"], ["1"], ["3"]]
Para encontrar o padrão correspondente:
str.to_enum(:scan,re).map {$&}
#> ["54m", "1t", "3r"]
str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]
é mais idiomático do questr.to_enum(:scan,re).map {$&}
/(\d+)[m-t]/
não /\d+[m-t]/
Escrever: re = /(\d+)[m-t]/; str.scan(re)
é o mesmo, str.scan(/(\d+)[mt]/)
mas recebo #> [["" 54 "], [" 1 "], [" 3 "]]
e não "54m", "1t", "3r"]
A pergunta era: se eu tenho uma expressão regular com um grupo e quero capturar todos os padrões sem alterar o padrão expressão (saindo do grupo), como posso fazer isso? Nesse sentido, uma solução possível, embora um pouco enigmática e difícil de ler, foi:str.to_enum(:scan,re).map {$&}
Você pode usar string.scan(your_regex).flatten
. Se o seu regex contiver grupos, ele retornará em uma única matriz simples.
string = "A 54mpl3 string w1th 7 numbers scatter3r ar0und"
your_regex = /(\d+)[m-t]/
string.scan(your_regex).flatten
=> ["54", "1", "3"]
Regex também pode ser um grupo nomeado.
string = 'group_photo.jpg'
regex = /\A(?<name>.*)\.(?<ext>.*)\z/
string.scan(regex).flatten
Você também pode usar gsub
, é apenas mais uma maneira se você quiser o MatchData.
str.gsub(/\d/).map{ Regexp.last_match }
your_regex = /(\d+)[m-t]/
e você não precisará usá-lo flatten
. Seu exemplo final usa last_match
que, nesse caso, provavelmente é seguro, mas é global e pode ser substituído se qualquer expressão regular corresponder antes da chamada last_match
. Em vez disso, é provavelmente mais seguro de usar string.match(regex).captures # => ["group_photo", "jpg"]
ou string.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]
como mostrado em outras respostas, dependendo do padrão e das necessidades.