-3

I am trying to get an explanation to what is happening in this line of code:

info["phone"] = info["phone"].gsub!(/\D/,"").scan(/1?(\d{3})(\d{3})(\d{4})/).join('.')

If a phone number is given such as 1-999-999-9999, (999)999-9999, or any combination put there.

Jørgen R
  • 9,179
  • 7
  • 36
  • 56
  • Related (not duplicate): http://stackoverflow.com/questions/22937618/reference-what-does-this-regex-mean – NightShadeQueen Jul 27 '15 at 22:44
  • 1
    http://meta.stackoverflow.com/a/253896/2988 – Jörg W Mittag Jul 27 '15 at 23:09
  • That code isn't correctly written to start. The regex can be figured out by reading through the Regexp documentation and/or using [one of the many](https://www.regex101.com/r/xO3iJ7/1) Regular Expression parsers on the internet. Glance at `scan` and `join` and you'll be done. – the Tin Man Jul 28 '15 at 00:07

2 Answers2

2

String#gsub is used to replace a specific text with another string. For example, "hello world".gsub(/hello/, "goodbye") would result in "goodbye world". The non-bang variant, gsub, does not modify the string itself; whereas the bang variant, gsub!, does:

test = "hello world"
test.gsub(/h[ae]ll[ou]/, "goodbye") # => "goodbye world"
test # => "hello world"
test.gsub!(/h[ae]ll[ou]/, "goodbye") # => "goodbye world"
test # => "goodbye world"

String#scan "scans" the string for a certain pattern, and returns an array of occurrences. This is useful for extracting certain things from a string:

tweet = "@github @you hello, world!"
tweet.scan(/@[\w]+/) # => ["@github", "@you"]

However, if you include groups within the scan, it returns an array of an array of group matches:

tweet.scan(/@([\w]+)/) # => [["github", "you"]]

So, what .gsub!(/\D/, "") does is it removes all non-digit characters from the string, and modifies the string (this last bit isn't really important right now). .scan looks for a phone number from the input (a phone number being an optional 1, followed by a set of three digits, followed by a set of three digits, followed by a set of four digits). Since it removes all non-digits from the input, it will attempt create a phone number from the first 10 or 11 numbers in the input, and for every 10 or 11 numbers past that.

However, the join joins together the sets of digits into a single string, 999.999.9999. But if there are multiple phone numbers in the input, it will end up joining those phone numbers with a period, too.

Hope that helps.

Jeremy Rodi
  • 2,295
  • 1
  • 18
  • 38
0

info["phone"] = info["phone"].stuff - replace the original in the array/hash/whatever

.gsub!(/\D/,"") - remove all non-Digits, such as parentheses or hyphens. (note that you don't need the ! in the gsub!)

.scan(/1?(\d{3})(\d{3})(\d{4})/) - Country code of 1 at the beginning. Then three digits are in the first matching group. Then three digits in the second matching group, then 4 in the last. The groups get put into an Array.

.join('.') - combine all elements of the array and make a string with dots between.

So...

'1+(555)123-4567' would get changed to '555.123.4567'

Andy
  • 270
  • 2
  • 12