Is There a Gem That Normalizes and Format Us Phone Numbers in Ruby

Is there a gem that normalizes and format US phone numbers in ruby?

Earlier this year, I reviewed a bunch of ruby gems that parse and format phone numbers. They fall into a number of groups (see below). TLDR: I used 'phone'. It might work for you because you can specify a default country code that it uses if your phone number doesn't include one.

1) US-centric:

big-phoney (0.1.4)

phone_wrangler (0.1.3)

simple_phone_number (0.1.9)

2) depends on rails or active_record:

phone_number (1.2.0)

validates_and_formats_phones (0.0.7)

3) forks of 'phone' that have been merged back into the trunk:

elskwid-phone (0.9.9.4)

tfe-phone (0.9.9.1)

4) relies on you to know the region ahead of time

phoney (0.1.0)

5) Kind of almost works for me

phone (0.9.9.3)

6) does not contain the substring 'phone' in the gem name (edit: I see you tried this one)

phony (1.6.1)

These groupings may be somewhat unfair or out of date so feel free to comment. I must admit I was a little frustrated at the time at how many people had partially re-invented this particular wheel.

Output integer as phone number format in view

You can use number_to_phone helper, like this:

<% if @post.phone.present? %>
<h4>Phone: <small> <%= number_to_phone @post.phone %><br></h4>
<% end %>

By default, it formats the phone number as xxx-xxx-xxxx :

2.1.1 :009 > number_to_phone(1235551234)  
=> "123-555-1234"
2.1.1 :010 > number_to_phone("1235551234")
=> "123-555-1234"

Validating phone number in ruby

There are many gems that will do this for you.

Take a look at: http://rubygems.org/search?utf8=%E2%9C%93&query=phone+number

This one looks like it will do what you need -- it essentially implements a regex to validate the phone number: http://rubygems.org/gems/validates_phone_number

For US, Canada (Bermuda, Bahamas... etc and all +1 numbers) there are other rules that the regex should follow. The first digit (after the +1) must be 2-9.

For a full list see: http://en.wikipedia.org/wiki/North_American_Numbering_Plan

Pure ruby UK phone number validator

If you want to avoid gems and regexes, you're doing Rails in hard mode. I would strongly suggest you devote some time to getting comfortable with both.

Parsing phone numbers is always more complicated than you think. For example, your assumption that "UK phone numbers are 11 digits long when in the 07... format and always have 7 after the prefix (whether it's +44, 44 or 0)" is not correct. 07 is just a really common prefix.

It's best to leave it as someone else's problem, so if there's a gem use it. For example, uk-phone-number-formatter seems to do exactly what you want and it is tiny.


Let's say we do this without regexes and without gems and assume 07 is the only prefix. First, separate the problem into two steps.

  1. Normalization
  2. Validation

Normalization is reformatting the phone number so that equivalent phone numbers look the same. Validation is validating its a phone number. Validation is much easier if the data has already been normalized.

That means stripping everything that isn't a digit, fixing the prefx, and adding the + at the front.

Stripping everything that isn't a digit is easy with gsub: phone.gsub!(/\D+/). Or the non-regex delete: phone.delete('^0-9').

Now with non-numbers out of the way, we just want to change "07" into "447".

Finally, add the +.

def normalize(phone)
# Strip non-digits.
normalized = phone.delete('^0-9')

# Replace 07x with 447x
if normalized[0..1] == "07"
normalized[0] = "44"
end

# Add the plus.
return "+#{normalized}"
end

Now that it's normalized, validation is easy.

# We assume the phone number is validated.
def phone_is_uk_format(phone)
errors.add(:phone, :missing_prefx, message: "Missing +447 prefix")
if normalized[0..3] != "+447"

# 12 because of the leading +
errors.add(:phone, :wrong_length, message: "A phone number is 11 digits")
if normalized.length != 12
end

And integrating it with a model...

class Person < ApplicationRecord
validate :phone_is_uk_format

# Normalize the phone number when it is set.
def phone=(number)
super(normalize_uk_phone(number))
end

private def phone_is_uk_format
# Validating presence is different.
return if phone.blank?

errors.add(:phone, :missing_prefx, message: "Missing +447 prefix")
if phone[0..3] != "+447"

# 12 because of the leading +
errors.add(:phone, :wrong_length, message: "A phone number is 11 digits")
if phone.length != 12
end

private def normalize_uk_phone(phone)
# Strip non-digits.
normalized = phone.delete('^0-9')

# Replace 07x with 447x
if normalized[0..1] == "07"
normalized[0] = "44"
end

# Add the plus.
return "+#{normalized}"
end
end

Better way to extract phone number and reformat?

Here's a much simpler approach using only regexes and substitution:

def extract_phone_number(input)
if input.gsub(/\D/, "").match(/^1?(\d{3})(\d{3})(\d{4})/)
[$1, $2, $3].join("-")
end
end

This strips all non-digits (\D), skips an optional leading one (^1?), then extracts the first remaining 10 digits in chunks ((\d{3})(\d{3})(\d{4})) and formats.

Here's the test:

test_data = {
"+1 480-874-4666" => "480-874-4666",
"404-581-4000" => "404-581-4000",
"(805) 682-4726" => "805-682-4726",
"978-851-7321, Ext 2606" => "978-851-7321",
"413- 658-1100" => "413-658-1100",
"(513) 287-7000,Toll Free (800) 733-2077" => "513-287-7000",
"1 (813) 274-8130" => "813-274-8130",
"212-363-3200,Media Relations: 212-668-2251." => "212-363-3200",
"323/221-2164" => "323-221-2164",
"" => nil,
"foobar" => nil,
"1234567" => nil,
}

test_data.each do |input, expected_output|
extracted = extract_phone_number(input)
print "FAIL (expected #{expected_output}): " unless extracted == expected_output
puts extracted
end

Phone Number Regex in Ruby -- Anchor error with ^$

The issue is at this line

VALID_PHONE_NUMBER_REGEX = /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/

it should be changed to

VALID_PHONE_NUMBER_REGEX = /\A(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}\z/

Personally, I would suggest to avoid trying to use a single regex to validate all those formats. Either group similar formats, and use different regexps, or normalize the input and validate a few formats.

You may also want to have a look at Phony.

How to format a phone number on a website, so that it can be dialed when clicked on a mobile browser?

While it is not a standard, you can try something similar to the following:

<a href="tel:1-408-555-5555">1-408-555-5555</a>

This works for iOS based devices, however, and may not be supported by other devices. http://beradrian.wordpress.com/2010/01/15/special-links/ discusses some other link formats which may be available in other devices, e.g. wtai://... callto://...

The downside to this approach is that you will have to test on multiple devices and potentially have to detect which device is accessing the page and display a different link/value depending on the specific client.



Related Topics



Leave a reply



Submit