# Does anyone have any good 'phone' validation routines?

**URL:** <https://www.ruby-forum.com/t/does-anyone-have-any-good-phone-validation-routines/120790>\
**Category:** Rails\
**Created:** [November 20, 2007, 5:40pm UTC](https://www.ruby-forum.com/t/does-anyone-have-any-good-phone-validation-routines/120790 "2007-11-20T17:40:20Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [November 20, 2007, 5:40pm UTC](https://www.ruby-forum.com/t/does-anyone-have-any-good-phone-validation-routines/120790/1 "2007-11-20T17:40:20Z")

</div>

I’m on the final stages of a large project and am now going through  
all the model validations. I’ve got many of them and am happy to share  
if anyone’s in need.  
I’d like to find a good, practical PHONE validation if anyone has one  
and is willing to share. I’ve done an exhaustive Google search and  
surprisingly, they elude me???  
Thank you,  
Kathy

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [November 20, 2007, 5:52pm UTC](https://www.ruby-forum.com/t/does-anyone-have-any-good-phone-validation-routines/120790/2 "2007-11-20T17:52:03Z")

</div>

On Nov 20, 2007 10:39 AM, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> I’m on the final stages of a large project and am now going through  
> all the model validations. I’ve got many of them and am happy to share  
> if anyone’s in need.  
> I’d like to find a good, practical PHONE validation if anyone has one  
> and is willing to share. I’ve done an exhaustive Google search and  
> surprisingly, they elude me???  
> Thank you,  
> Kathy

I usually just remove all the punctuation, then make sure I have the  
proper number of digits left.

> > phone = ‘(615) 867-5309’  
> > =\> “(615) 867-5309”  
> > phone.gsub( /[^\d]/, ‘’ ).size == 10  
> > =\> true

–  
Greg D.  
[http://destiney.com/](http://destiney.com/)

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [November 20, 2007, 6:10pm UTC](https://www.ruby-forum.com/t/does-anyone-have-any-good-phone-validation-routines/120790/3 "2007-11-20T18:10:48Z")

</div>

On Nov 20, 2007, at 10:51 AM, Greg D. wrote:

> I usually just remove all the punctuation, then make sure I have the  
> proper number of digits left.

That’s what I do too, and it works in my case, but it can be  
ambiguous. For instance, using the + convention for international codes,

+506 123-4567  
From a US point of view that’s a phone number in Costa Rica, while

(506) 123-4567  
is a phone number in Canada.

It’s a stretch, admittedly, but something to be aware of.

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [November 20, 2007, 8:24pm UTC](https://www.ruby-forum.com/t/does-anyone-have-any-good-phone-validation-routines/120790/4 "2007-11-20T20:24:38Z")

</div>

Hi –

On Tue, 20 Nov 2007, Greg W. wrote:

> I wrote this yesterday. Not so much a validation, but rather a  
> – gw (www.railsdev.ws)
> 
> end  
> You’re doing way too much work 🙂 This should give you the same  
> thing:

def   
@phone\_number = chars.gsub(/\D/, “”)  
end

(And cAmElCaSe removal thrown in free 🙂

The use of [] to set the phone number seems a little odd to me.  
Anyway…

> elsif (numberLength \< 7) || (numberLength == 8) || (numberLength  
> formattedNumber += ‘-’
> 
> else
> 
> ```
> if @phoneNumber[0,3] != '000'
> formattedNumber += @phoneNumber[0,3] + format
> end
> formattedNumber += @phoneNumber[3,3]
> formattedNumber += format
> formattedNumber += @phoneNumber[6,4]
> 
> ```
> 
> end

Here you’re working too hard, too, and repeating too much code. I  
understand that you want to keep the different cases separate, so that  
it’s easier to add new cases (rather than come up with some very  
intricate way to construct the string that would be too easy to  
break). Even with that in mind, you could get this much more  
consolidated and unrepetitive:

if format == ‘(’  
ac = ‘(’ + areacode + ') ’  
sep = ‘-’

```
elsif format == '/'
  ac = areacode + '/'
  sep = '-'

else
  ac = areacode + format
  sep = format

end

formatted_number << ac if has_areacode?
formatted_number << join_exchange_and_number(sep)

```

Or if you wanted to you could use a case statement, and/or do the  
assignments directly from the case or conditional:

ac, sep = case format  
when ‘(’ then [‘(’+areacode + ') ', ‘-’]  
when ‘/’ then [areacode + ‘/’, ‘-’]  
else [areacode + format, format]  
end

formatted\_number \<\< ac if has\_areacode?  
formatted\_number \<\< join\_exchange\_and\_number(sep)

That would be easy to add cases to. And of course you would need:

def join\_exchange\_and\_number(sep=‘-’)  
@phone\_number[3,3] \<\< sep \<\< @phone\_number[6,4]  
end

def has\_area\_code?  
areacode != ‘000’  
end

Note: I’ve only tested these code snippets to the extent of looking  
quickly at screen output of your examples. Hopefully they’ll give you  
some useful ideas.

David

–  
Upcoming training by David A. Black/Ruby Power and Light, LLC:

- Advancing With Rails, Berlin, Germany, November 19-22
- Intro to Rails, London, UK, December 3-6 (by Skills Matter)  
See [http://www.rubypal.com](http://www.rubypal.com) for details!

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [November 20, 2007, 6:43pm UTC](https://www.ruby-forum.com/t/does-anyone-have-any-good-phone-validation-routines/120790/5 "2007-11-20T18:43:09Z")

</div>

On Nov 20, 2007, at 8:39 AM, removed\_email\_address@domain.invalid wrote:

> I’m on the final stages of a large project and am now going through  
> all the model validations. I’ve got many of them and am happy to share  
> if anyone’s in need.  
> I’d like to find a good, practical PHONE validation if anyone has one  
> and is willing to share. I’ve done an exhaustive Google search and  
> surprisingly, they elude me???

I wrote this yesterday. Not so much a validation, but rather a  
PhoneNumber class. Strips all non-numerics upon instantiation.  
Intended to store the number as a packed (unformatted) string of  
digits and then to be formatted upon display (so your app has a  
uniform display of humbers from all input sources). Has a few  
different formatting options. Optimized for US style numbers at this  
point.

If you’re just interested in the part that strips the non-numerics,  
see the [] method near the top.

– gw (www.railsdev.ws)

class PhoneNumber

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

def set(chars)  
self.[] chars  
end

def [] (chars)  
charSet = chars.dup.split("")  
charSet.delete\_if do |char|  
(char =~ /\d/) == nil  
end  
@phoneNumber = charSet.join  
end

#: -  
#------------------------------------------------------------  
def to\_s  
return @phoneNumber.to\_s  
end

def raw  
@phoneNumber  
end

def areacode  
return @phoneNumber[0,3]  
end

def prefix  
return @phoneNumber[3,3]  
end

def number  
return @phoneNumber[6,4]  
end

def extension  
return @phoneNumber[10,6]  
end

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

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

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

formattedNumber = String.new  
numberLength = @phoneNumber.size

if (numberLength == 7)  
@phoneNumber = ‘000’ + @phoneNumber  
elsif (numberLength \< 7) || (numberLength == 8) || (numberLength  
== 9) || (numberLength \> 16)  
return @phoneNumber  
end

if format == ‘(’

```
 if @phoneNumber[0,3] != '000'
   formattedNumber += '(' + @phoneNumber[0,3] + ') '
 end
 formattedNumber += @phoneNumber[3,3]
 formattedNumber += '-'
 formattedNumber += @phoneNumber[6,4]

```

elsif format == ‘/’

```
 if @phoneNumber[0,3] != '000'
   formattedNumber += @phoneNumber[0,3] + '/'
 end
 formattedNumber += @phoneNumber[3,3]
 formattedNumber += '-'
 formattedNumber += @phoneNumber[6,4]

```

else

```
 if @phoneNumber[0,3] != '000'
   formattedNumber += @phoneNumber[0,3] + format
 end
 formattedNumber += @phoneNumber[3,3]
 formattedNumber += format
 formattedNumber += @phoneNumber[6,4]

```

end

if @phoneNumber.size \> 10  
formattedNumber += ’ x’  
formattedNumber += @phoneNumber[10,6]  
end

return formattedNumber

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)  
@phoneNumber = pack(parts)  
end

end

=begin

# USAGE EXAMPLES:

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

# or

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

puts home.raw  
puts home.areacode  
puts home.prefix  
puts home.number  
puts home.extension  
puts home.formatted  
puts home.formattedWith(’(’)  
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

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [November 20, 2007, 11:06pm UTC](https://www.ruby-forum.com/t/does-anyone-have-any-good-phone-validation-routines/120790/6 "2007-11-20T23:06:33Z")

</div>

On Nov 20, 2007, at 11:23 AM, David A. Black wrote:

> On Tue, 20 Nov 2007, Greg W. wrote:

> def   
> @phone\_number = chars.gsub(/\D/, “”)  
> end
> 
> (And cAmElCaSe removal thrown in free 🙂

Yeah, Ruby does regex stuff like this different than my prev  
language, so I still have some cause & effect experimenting to do.  
Plus, I have blocks on the brain of course. Thanks for this one.  
Cleaner for sure 🙂

I absolutely despise underscores between words in variables – that  
one is going to be a very hard one for me, and for the moment I am  
ignoring it. I’m sure after I’ve spent more time looking at Ruby  
code, I’ll get more accustomed to it. At the moment, it’s slows me  
down too much to be constantly fixing typos because I instinctually  
camel case. I’ll get over myself eventually.

> The use of [] to set the phone number seems a little odd to me.

As the entirely of the object data is just a simple string, I was  
trying to find a way to not have to use an attribute during  
assignment so it felt like the assignent was to the object as a whole  
just like a string would be.

I’m still muddling my way through what Ruby can do (and of course  
what should be done regardless of the “can”), and experimenting with  
how to make things look & feel a certain way in Ruby.

> Anyway…
> 
> > if format == ‘(’
> > 
> > ```
> > if @phoneNumber[0,3] != '000'
> > formattedNumber += '(' + @phoneNumber[0,3] + ') '
> > end
> > formattedNumber += @phoneNumber[3,3]
> > formattedNumber += '-'
> > formattedNumber += @phoneNumber[6,4]
> > 
> > ```

> Here you’re working too hard, too, and repeating too much code.

Yeah, I know. I started making cases, and hadn’t gotten around to  
reducing them. Brand new to Ruby, so not yet equipped to solve every  
instance of “hard work” all at the same time. I’ll focus on objective  
X even if that leaves objective Y hacked up for the time being. I  
actually should have known better than to leave in that particular  
dose of obvious repetitive coding, but I just wasn’t focused on that  
part of it.

> Note: I’ve only tested these code snippets to the extent of looking  
> quickly at screen output of your examples. Hopefully they’ll give you  
> some useful ideas.

Yes, I appreciate the critique – thanks.

– gw (www.railsdev.ws)
