Devuelve el primer partido de Ruby regex

97

Estoy buscando una forma de realizar una coincidencia de expresiones regulares en una cadena en Ruby y hacer que se produzca un cortocircuito en la primera coincidencia.

La cadena que estoy procesando es larga y, por lo que parece, la forma estándar ( matchmétodo) procesa todo, recopila cada coincidencia y devuelve un objeto MatchData que contiene todas las coincidencias.

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

Respuestas:

134

Podrías intentarlo variableName[/regular expression/]. Esta es una salida de ejemplo de 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"
Presidenten
fuente
¿No es esto hacer un partido y devolver el primer resultado detrás de escena?
Gishu
7
Después de algunas evaluaciones comparativas con cadenas de varias longitudes y mirando la fuente C, resulta que Regex.match hace un cortocircuito y solo encuentra la primera coincidencia.
Daniel Beardsley
3
Ordenado, no sabía nada de este atajo.
Pierre
¿Existe alguna documentación sobre este atajo? Busqué alto y bajo para lo que pensé que era una tarea relativamente simple y solo resolví mi problema después de encontrar esto. ¡Gracias!
dmourati
5
@dmourati Puede encontrar esta característica documentada en String # [] . Gracias por preguntar sobre el documento, porque al leerlo encontré el captureargumento, que te permite devolver una captura en lugar de la coincidencia completa.
oso perezoso
68

Puedes usar []: (que es 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
fuente
4
mejor respuesta completa
akostadinov
23

Si solo la existencia de una coincidencia es importante, puede ir con

/regexp/ =~ "string"

De cualquier manera, matchsolo debe devolver el primer resultado, mientras scanbusca en toda la cadena. Por tanto, si

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

Todavía no estoy seguro de si esta característica es increíble o simplemente totalmente loca, pero su expresión regular puede definir variables locales.

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

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

Felix
fuente
¡Característica impresionante! Justo lo que necesitaba
RaphaMex
Advertencia: solo funciona cuando regex =~ string", not when string = ~ regex`
Christopher Oezbek
2

Una expresión regular (regex) no es más que una máquina de estados finitos (FSM).

Un FSM intenta responder a la pregunta "¿Es este estado posible o no?"

Sigue intentando hacer coincidir un patrón hasta que se encuentra una coincidencia (éxito), o hasta que se exploran todas las rutas y no se encuentra ninguna coincidencia (error).

Sobre el éxito, la pregunta "¿Es este estado posible o no?" ha sido respondido con un "sí". Por lo tanto, no se necesitan más coincidencias y la expresión regular regresa.

Vea esto y esto para más sobre esto.

Además: aquí hay un ejemplo interesante para demostrar cómo funciona la expresión regular. Aquí, se usa una expresión regular para detectar si un número dado es primo. Este ejemplo está en perl, pero también se puede escribir en ruby.

Tornasol
fuente