How to parse and normalize U.S. phone number

I have an app that asks a user to enter a 10 digit phone number…

To make things easy for the user, the input field is a single text
box.

I’d like to turn whatever the user enters into xxx-xxx-xxxx whether
they enter xxxxxxxxxx or (xxx)xxx-xxxx or (xxx)xxxxxx you get the
idea…

Is there any code out there that does this already? With so many
consumer apps out there, I am sure I’m sure this problem has been
solved many times over :slight_smile:

Thanks.

On Jun 6, 2008, at 11:32 PM, nahabed wrote:

I have an app that asks a user to enter a 10 digit phone number…

To make things easy for the user, the input field is a single text
box.

I’d like to turn whatever the user enters into xxx-xxx-xxxx whether
they enter xxxxxxxxxx or (xxx)xxx-xxxx or (xxx)xxxxxx you get the
idea…

This will get you started.

I suggest you store only the digits and pretty it up when you display
it, using number_to_phone
http://railsmanual.com/module/ActionView::Helpers::NumberHelper#number_to_phone

On Jun 6, 2008, at 10:32 PM, nahabed wrote:

consumer apps out there, I am sure I’m sure this problem has been
solved many times over :slight_smile:

Indeed. This one does lots of things from dealing with single fields
to dealing with three-field UIs. It also allows it to be displayed in
a few formats.

It’s one of the first Ruby things I wrote, so it’s not entirely
deconstructed to eliminate all redundancies, and may be some non-
idiomatic stuff.

I use this as a composition in my models with supporting code like so:

def phone_number
PhoneNumber.new(super)
end

def phone_number=(phone)
super PhoneNumber.new(phone).to_s
end

– gw

class PhoneNumber

#------------------------------------------------------------
def initialize(parts=’’)
self.[] parts
end

def set(parts)
self.[] parts
end

def [] (parts)
if parts.is_a?(String)
@phone_number = parts.gsub(/\D/,’’)
elsif parts.is_a?(Hash)
self.pack!(parts)
end
end

#: -
#------------------------------------------------------------
def to_s
return @phone_number.to_s
end

def raw
@phone_number
end

def has_areacode?
areacode != ‘000’
end

def areacode
return @phone_number[0,3]
end

def prefix
return @phone_number[3,3]
end

def number
return @phone_number[6,4]
end

def extension
return @phone_number[10,6]
end

#:-
#------------------------------------------------------------
def formatted(format=’-’)
return self.formatted_with(format)
end

#------------------------------------------------------------
def formatted_with(format=’-’)

formats any number with at least 7 digits and a maximum of 16

formatted_number = String.new
number_length = @phone_number.size

if (number_length == 7)
@phone_number = ‘000’ + @phone_number
elsif (number_length < 7) || (number_length == 8) ||
(number_length == 9) || (number_length > 16)
return @phone_number
end

if format == ‘(’
separator = ‘-’
formatted_areacode = ‘(’ + areacode + ') ’

elsif format == ‘/’
separator = ‘-’
formatted_areacode = areacode + ‘/’

else
separator = format
formatted_areacode = (areacode + separator)
end

formatted_number += formatted_areacode
formatted_number += @phone_number[3,3]
formatted_number += separator
formatted_number += @phone_number[6,4]

if @phone_number.size > 10
formatted_number += ’ x’
formatted_number += @phone_number[10,6]
end

return formatted_number

end

#------------------------------------------------------------
def unpack
return {
:areacode => self.areacode,
:prefix => self.prefix,
:number => self.number,
:extension => self.extension}
end

#------------------------------------------------------------
def pack(parts)

phArea = ‘’
phPrefix = ‘’
phNumber = ‘’
phExtension = ‘’

if parts.size >= 3
if parts.is_a?(Array)
phArea = parts[0].to_s
phPrefix = parts[1].to_s
phNumber = parts[3].to_s
if parts.size == 4
phExtension = parts[4].to_s
end
elsif parts.is_a?(Hash)
phArea = parts[:areacode].to_s
phPrefix = parts[:prefix].to_s
phNumber = parts[:number].to_s
phExtension = parts[:extension].to_s
end
end

return phArea + phPrefix + phNumber + phExtension

end

#------------------------------------------------------------
def pack!(parts)
@phone_number = pack(parts)
end

end

=begin

home = PhoneNumber.new(‘800/555-2468 x012’)

or

home = PhoneNumber.new
home[‘800/555-2468 x012’]

or

home = PhoneNumber.new

({:areacode=>‘800’, :prefix=>‘555’, :number=>‘2020’})

puts home.raw
puts home.areacode
puts home.prefix
puts home.number
puts home.extension
puts home.formatted
puts home.formatted_with(’(’)
puts home.formatted_with(’.’)
puts home.formatted_with(’/’)
puts home.to_s
puts home.pack({:areacode=>‘555’, :prefix=>‘888’, :number=>‘1212’})
p home.unpack
puts home.pack!({:areacode=>‘555’, :prefix=>‘888’, :number=>‘1212’})
puts home.formatted

=end