Feature #6802
openString#scan should have equivalent yielding MatchData
Description
Ruby should have method to obtain not an array of arrays but of MatchData objects. It can help in obtaining named groups:
pattern = /x: (?\d+) y:(?\d+)/
polygon = []
text.scan_for_pattern(pattern){|m| polygon << Point.new(m[:x], m[:y]) }
Not to break existing code we need unique name. Ideas? May be #each_match
        
           Updated by prijutme4ty (Ilya Vorontsov) over 13 years ago
          Updated by prijutme4ty (Ilya Vorontsov) over 13 years ago
          
          
        
        
      
      Simple implementation:
class String
def each_match(pattern, &block)
return Enumerator.new(self, :each_match, pattern)  unless block_given?
text = self
m = text.match(pattern)
while m
yield m
text = text[m.end(0)..-1]
m = text.match(pattern)
end
end
end
        
           Updated by Eregon (Benoit Daloze) over 13 years ago
          Updated by Eregon (Benoit Daloze) over 13 years ago
          
          
        
        
      
      =begin
You can use (({String#scan})) with the block form and (({$~})) (as well as other Regexp-related globals) for this:
> text="x:1 y:12 ; x:33 y:2"
> text.scan(/x:(?<x>\d+) y:(?<y>\d+)/) { p [$~[:x],$~[:y]] }
["1", "12"]
["33", "2"]
Please check your Regexp and give an example of (({text})) next time.
=end
        
           Updated by prijutme4ty (Ilya Vorontsov) over 13 years ago
          Updated by prijutme4ty (Ilya Vorontsov) over 13 years ago
          
          
        
        
      
      Thank you for a solution! I always forgot about regexp global vars. Though I suggest that using a special method here is more clear. So what'd you say about String#each_match and Regexp#each_match
Yes, implementation is as simple as
class String
def each_match(pat)
scan(pat){ yield $~ }
end
end
and similar for Regexp.
Eregon (Benoit Daloze) wrote:
=begin
You can use (({String#scan})) with the block form and (({$~})) (as well as other Regexp-related globals) for this:> text="x:1 y:12 ; x:33 y:2" > text.scan(/x:(?<x>\d+) y:(?<y>\d+)/) { p [$~[:x],$~[:y]] } ["1", "12"] ["33", "2"]Please check your Regexp and give an example of (({text})) next time.
=end
        
           Updated by trans (Thomas Sawyer) over 13 years ago
          Updated by trans (Thomas Sawyer) over 13 years ago
          
          
        
        
      
      +1 I have definitely used this before (as Facets' #mscan).
        
           Updated by Eregon (Benoit Daloze) over 13 years ago
          Updated by Eregon (Benoit Daloze) over 13 years ago
          
          
        
        
      
      prijutme4ty (Ilya Vorontsov) wrote:
Though I suggest that using a special method here is more clear.
So what'd you say about String#each_match and Regexp#each_match
I did indeed somewhat expected String#scan to yield a MatchData object, instead of $.captures. is not the prettiest thing around).
I'm in favor of String#each_match, it might be a nice addition and the name is clear, but the naming is different from the usual regexp methods on String, and it might not be worth to add a method (I agree $
I think Regexp#each_match does not convey well what it does though.
        
           Updated by tomoakin (Tomoaki Nishiyama) about 13 years ago
          Updated by tomoakin (Tomoaki Nishiyama) about 13 years ago
          
          
        
        
      
      
    
        
           Updated by mame (Yusuke Endoh) almost 13 years ago
          Updated by mame (Yusuke Endoh) almost 13 years ago
          
          
        
        
      
      - Status changed from Open to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
- Target version set to 2.6
        
           Updated by naruse (Yui NARUSE) almost 8 years ago
          Updated by naruse (Yui NARUSE) almost 8 years ago
          
          
        
        
      
      - Target version deleted (2.6)
        
           Updated by shyouhei (Shyouhei Urabe) almost 7 years ago
          Updated by shyouhei (Shyouhei Urabe) almost 7 years ago
          
          
        
        
      
      - Related to Feature #12745: String#(g)sub(!) should pass a MatchData to the block, not a String added