Using Ruby’s Scan Method to Transform Strings


In the last post, I came across the line below that worked fine but I wanted to make it more compact and introduce some reusability for the future.

The problem that needed to be solved was to take a three character string and convert it to a six character string by duplicating each of the characters while keeping the duplicated characters together.

For example, the string ‘fd3’ should become ‘ffdd33’.

After looking through the Ruby Docs for the String class, I came across the scan method that looked like it would help solve the problem.

The explanation of the scan method from the Ruby Docs:

scan(pattern) → array
scan(pattern) {|match, …| block } → str

Both forms iterate through str, matching the pattern (which may be a Regexp or a String). For each match, a result is generated and either added to the result array or passed to the block. If the pattern contains no groups, each individual result consists of the matched string, $&. If the pattern contains groups, each individual result is itself an array containing one entry per group.

To get to the end result, the following steps were used:

1.  Use a regex to match each individual character and return an array of the characters.

?> (‘f3d’).scan(/./)

=> [“f”, “3”, “d”]

2.  Because we want to keep the duplicated characters next to each other, the regex is changed to group each character by itself.

?> (‘f3d’).scan(/(.)/)
=> [[“f”], [“3”], [“d”]]

3.  Now that each character is grouped by itself, the regex can be used to duplicate each character.

?> (‘f3d’).scan(/((.))/)
=> [[“f”, “f”], [“3”, “3”], [“d”, “d”]]

4.  Flatten the array to remove the sub-arrays.

?> (‘f3d’).scan(/((.))/).flatten
=> [“f”, “f”, “3”, “3”, “d”, “d”]

5.  Join the elements to give us the result.

?> (‘f3d’).scan(/((.))/).flatten.join
=> “ff33dd”

The downside of this change is that the code might be considered less readable by some.  There is also a bit of premature optimization going on here but I think it’s not an unreasonable change because this code is more reusable if requirements change in the future.

In any case, I felt it was  a good way to demonstrate the power of the scan method and I think it works well for this application.


Please enter your comment!
Please enter your name here