validator regulares regular one expresiones examples ruby regex

regulares - ¿Cómo obtengo los datos de coincidencia para todas las apariciones de una expresión regular de Ruby en una cadena?



ruby regex validator (5)

Necesito el MatchData para cada aparición de una expresión regular en una cadena. Esto es diferente al método de escaneo sugerido en Match All Occurrences of a Regex , ya que eso solo me da una matriz de cadenas (necesito MatchData completo, para obtener información de inicio y final, etc.).

input = "abc12def34ghijklmno567pqrs" numbers = //d+/ numbers.match input # #<MatchData "12"> (only the first match) input.scan numbers # ["12", "34", "567"] (all matches, but only the strings)

Sospecho que hay algún método que he pasado por alto. Sugerencias?


Lo pondré aquí por si acaso para hacer que el código esté disponible a través de la búsqueda de google respectiva:

input = "abc12def34ghijklmno567pqrs" numbers = //d+/ input.gsub(numbers) { |m| p $~ }

El resultado es el siguiente:

⇒ #<MatchData "12"> ⇒ #<MatchData "34"> ⇒ #<MatchData "567">

Explicación detallada


Me sorprende que nadie haya mencionado la increíble clase StringScanner incluida en la biblioteca estándar de Ruby:

require ''strscan'' s = StringScanner.new(''abc12def34ghijklmno567pqrs'') while s.skip_until(//d+/) num, offset = s.matched.to_i, [s.pos - s.matched_size, s.pos - 1] # .. end

No, no le proporciona los objetos MatchData, pero le proporciona una interfaz basada en índices en la cadena.


Mi solución actual es agregar un método each_match a Regexp:

class Regexp def each_match(str) start = 0 while matchdata = self.match(str, start) yield matchdata start = matchdata.end(0) end end end

Ahora puedo hacer:

numbers.each_match input do |match| puts "Found #{match[0]} at #{match.begin(0)} until #{match.end(0)}" end

Dime que hay una mejor manera.


Usted quiere

"abc12def34ghijklmno567pqrs".to_enum(:scan, //d+/).map { Regexp.last_match }

que te da

[#<MatchData "12">, #<MatchData "34">, #<MatchData "567">]

El "truco" es, como ve, construir un enumerador para obtener cada last_match.


input = "abc12def34ghijklmno567pqrs" n = Regexp.new("//d+") [n.match(input)].tap { |a| a << n.match(input,a.last().end(0)+1) until a.last().nil? }[0..-2] => [#<MatchData "12">, #<MatchData "34">, #<MatchData "567">]