Cómo hacer coincidir todas las ocurrencias de una expresión regular
586
¿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.
¿Pero qué hay de este caso? "match me!". scan (/.../) = ["mat", "ch" "me!" ], pero todas las apariciones de /.../ serían ["mat", "atc", "tch", "ch", ...]
Michael Dickens
13
No, no lo sería. /.../ es una expresión regular codiciosa normal. No retrocederá en el contenido coincidente. podrías intentar usar una expresión regular perezosa, pero incluso eso probablemente no sea suficiente. eche un vistazo a regexp doc ruby-doc.org/core-1.9.3/Regexp.html para expresar correctamente su regexp :)
Jean
49
esto parece un Ruby WTF ... ¿por qué está esto en String en lugar de Regexp con las otras cosas de regexp? Ni siquiera se menciona en los documentos de Regexp
Anentropic el
99
Supongo que es porque está definido y llamado en String, no en Regex ... Pero en realidad tiene sentido. Puede escribir una expresión regular para capturar todas las coincidencias utilizando Regex # match e iterar sobre los grupos capturados. Aquí escribe una función de coincidencia parcial y desea que se aplique varias veces en una cadena determinada, esto no es responsabilidad de Regexp. Le sugiero que verifique la implementación del escaneo para una mejor comprensión: ruby-doc.org/core-1.9.3/String.html#method-i-scan
Jean
99
@MichaelDickens: en este caso, puede usar /(?=(...))/.
Konrad Borowski
67
Para encontrar todas las cadenas coincidentes, use el scanmétodo de String .
str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]es más idiomático questr.to_enum(:scan,re).map {$&}
el Hombre de hojalata
Tal vez lo malinterpretaste. La expresión regular del ejemplo de un usuario que respondí fue: /(\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 {$&}
MVP
-1
Puedes usar string.scan(your_regex).flatten. Si su expresión regular contiene grupos, regresará en una única matriz simple.
Elimine la agrupación de your_regex = /(\d+)[m-t]/y no necesitará usarla flatten. Su ejemplo final utiliza lo last_matchque 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.
Respuestas:
Usar
scan
debería hacer el truco:fuente
/(?=(...))/
.Para encontrar todas las cadenas coincidentes, use el
scan
método de String .Si lo desea,
MatchData
que es el tipo de objeto devuelto por elmatch
método Regexp , use:El beneficio de usar
MatchData
es que puedes usar métodos comooffset
:Vea estas preguntas si desea saber más:
La lectura sobre variables especiales
$&
,$'
,$1
,$2
en Ruby será útil también.fuente
si tienes una expresión regular con grupos:
puedes usar el
scan
método de String para encontrar grupos coincidentes:Para encontrar el patrón correspondiente:
fuente
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 mismostr.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.Regex también puede ser un grupo con nombre.
También puede usar
gsub
, es solo una forma más si desea MatchData.fuente
your_regex = /(\d+)[m-t]/
y no necesitará usarlaflatten
. Su ejemplo final utiliza lolast_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 llamarlast_match
. En cambio, probablemente sea más seguro usarlostring.match(regex).captures # => ["group_photo", "jpg"]
ostring.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]
como se muestra en otras respuestas, dependiendo del patrón y las necesidades.