You can capture them into an array with scan
, which will match all occurrences of your regex:
irb(main):001:0> s = 'every 15th of the month'
=> "every 15th of the month"
irb(main):003:0> s2 = 'every 21st and 28th of the month'
=> "every 21st and 28th of the month"
irb(main):004:0> s3 = 'every 21st, 22nd, and 28th of the month'
=> "every 21st, 22nd, and 28th of the month"
irb(main):006:0> myarray = s3.scan(/(\d{1,2}(?:st|nd|rd|th))/)
=> [["21st"], ["22nd"], ["28th"]]
irb(main):007:0> myarray = s2.scan(/(\d{1,2}(?:st|nd|rd|th))/)
=> [["21st"], ["28th"]]
irb(main):008:0> myarray = s.scan(/(\d{1,2}(?:st|nd|rd|th))/)
=> [["15th"]]
irb(main):009:0>
Then of course you can access each match using the typical myarray[index]
notation (or loop through all of them, etc).
Edit: Based on your comments, this is how I would do this:
ORDINALS = (1..31).map { |n| ActiveSupport::Inflector::ordinalize n }
DAY_OF_MONTH_REGEX = /(#{ORDINALS.join('|')})/i
myarray = string.scan(DAY_OF_MONTH_REGEX)
This really only gets tripped up by ordinal numbers that might appear in other phrases. Trying to get more restrictive than that will probably be pretty ugly, since you have to cover a bunch of different cases. Might be able to come up with something...but it probably wouldn't be worth it. If you want to parse the string with really fine-grained control and a variable amount of text to match, then this probably just isn't a job for regex, to be honest. It's hard to be certain without knowing what format the lines are, if this is coming from a file with other similar lines, if you have any control over the format/contents of the strings, etc.