Today I Learned

hashrocket A Hashrocket project

Ruby Scan with Index

If you want to search for a pattern in a string and get back all the matches of that pattern, you can use String#scan:

irb(main)> "..123...456...123".scan(/\d+/)
=> ["123", "456", "123"]

This is super useful. But sometimes, it would be even more useful to also know the index of where the match starts. Turns out, you can do this with $~

irb(main)> matches_with_index = []
irb(main)* "..123...456...123".scan(/\d+/).map do |x|
irb(main)*   [x, $~.offset(0)[0]]
irb(main)> end
irb(main)> matches_with_index
=> [["123", 2], ["456", 8], ["123", 14]]

$~ is a global variable that's equivalent to Regexp.last_match, which is the MatchData for the last successful pattern match - it basically lets you get some data about the last thing Regexp matched.

MatchData#offsetreturns an array with the starting and ending offsets of the match. So $~.offset(0)[0] -> the offset to the start of the match, and $~.offset(0)[1] -> the offset to the end of the match.

See More #ruby TILs
Looking for help? Each developer at Hashrocket has years of experience working with Ruby applications of all types and sizes. We're an active presence at Ruby conferences, have written some of the most popular gems, and have worked on many of the web's Ruby on Rails success stories. Contact us today to talk about your Ruby project.