4

I have the following case that does not work the way I expect, and, I am doing something wrong, but I cannot find out what that is. The script matches the four letter words within a sentence. I want to find a way to iterate over the matched groups.

x = "This is a statement with four letter words like this"
result = x.match /(\b\w{4}\b)/
=> #<MatchData "This" 1:"This"> 

Unfortunately, $1 contains "This", but this is all I get. $2 should contain "with" but it is nil. What am I doing wrong? Why is $2 nil? Why is $n with n>=2 nil?

sawa
  • 165,429
  • 45
  • 277
  • 381
p.matsinopoulos
  • 7,655
  • 6
  • 44
  • 92
  • I am not really sure what you are doing, but remember that regexp is not always the right tool for the job. You can also try something like x.split.select{|x| x.size == 4} – hirolau Oct 04 '13 at 09:00
  • @hirolau: Good point (the one about not always using regexps). Here, it depends on the definition of "word". `split` will not play nice with punctuation -- unless you use a regexp as delimiter ;-) – undur_gongor Oct 04 '13 at 09:11
  • True, yes the code works if you use the delimiter /\W+/ but then the original code is easier. – hirolau Oct 04 '13 at 09:18

1 Answers1

5

This is because your regexp matches just once and contains just one capture group.

You probably want:

x.scan /\b\w{4}\b/

which will give you an array of all matches.

$1, $2 ... are set to the groups in a single match of the regexp, e.g.

x.match(/(\b\w{4}\b).*(\b\w{4}\b)/)

sets $1 to 'This' and $2 to 'this'.

The groups can also be accessed through $~[1], $~[2], ... or Regexp.last_match[1] ...

undur_gongor
  • 15,657
  • 5
  • 63
  • 75