¿Hay alguna forma rápida de encontrar todas las coincidencias de una expresión regular en Ruby? Miré a través del objeto Regex en Ruby STL y busqué en Google en vano.
¿Hay alguna forma rápida de encontrar todas las coincidencias de una expresión regular en Ruby? Miré a través del objeto Regex en Ruby STL y busqué en Google en vano.
Respuestas:
Usar scan
debería hacer el truco:
string.scan(/regex/)
/(?=(...))/
.
Para encontrar todas las cadenas coincidentes, use el scan
método de String .
str = "A 54mpl3 string w1th 7 numb3rs scatter36 ar0und"
str.scan(/\d+/)
#=> ["54", "3", "1", "7", "3", "36", "0"]
Si lo desea, MatchData
que es el tipo de objeto devuelto por el 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">]
El beneficio de usar MatchData
es que puedes 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]
Vea estas preguntas si desea saber más:
La lectura sobre variables especiales $&
, $'
, $1
, $2
en Ruby será útil también.
si tienes una expresión regular con grupos:
str="A 54mpl3 string w1th 7 numbers scatter3r ar0und"
re=/(\d+)[m-t]/
puedes usar el scan
método de String para encontrar grupos coincidentes:
str.scan re
#> [["54"], ["1"], ["3"]]
Para encontrar el patrón correspondiente:
str.to_enum(:scan,re).map {$&}
#> ["54m", "1t", "3r"]
str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]
es más idiomático questr.to_enum(:scan,re).map {$&}
/(\d+)[m-t]/
no /\d+[m-t]/
Escribir: re = /(\d+)[m-t]/; str.scan(re)
es lo mismo str.scan(/(\d+)[mt]/)
pero obtengo #> [["" 54 "], [" 1 "], [" 3 "]]
y no "54m", "1t", "3r"]
La pregunta fue: si tengo una expresión regular con un grupo y quiero capturar todos los patrones sin cambiar el patrón regular expresión (dejando el grupo), ¿cómo puedo hacerlo? En este sentido, una posible solución, aunque un poco críptica y difícil de leer, fue:str.to_enum(:scan,re).map {$&}
Puedes usar string.scan(your_regex).flatten
. Si su expresión regular contiene grupos, regresará en una única matriz simple.
string = "A 54mpl3 string w1th 7 numbers scatter3r ar0und"
your_regex = /(\d+)[m-t]/
string.scan(your_regex).flatten
=> ["54", "1", "3"]
Regex también puede ser un grupo con nombre.
string = 'group_photo.jpg'
regex = /\A(?<name>.*)\.(?<ext>.*)\z/
string.scan(regex).flatten
También puede usar gsub
, es solo una forma más si desea MatchData.
str.gsub(/\d/).map{ Regexp.last_match }
your_regex = /(\d+)[m-t]/
y no necesitará usarla flatten
. Su ejemplo final utiliza lo last_match
que en este caso es probablemente seguro, pero es global y posiblemente podría sobrescribirse si se combinara alguna expresión regular antes de llamar last_match
. En cambio, probablemente sea más seguro usarlo string.match(regex).captures # => ["group_photo", "jpg"]
o string.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]
como se muestra en otras respuestas, dependiendo del patrón y las necesidades.