Validating Telephone Numbers
December 13, 2011
When I was a kid, telephones had rotary dials, not push buttons, and exchanges had names; my grandmother was in the Underhill 8 exchange. If you were calling someone in the same exchange as you were, you only had to dial the last four digits of the number. Long distance calling generally involved a human operator.
Modern American telephone numbers have ten digits, segmented as a three-digit area code, a three-digit exchange code, and a four-digit number. Within an area code, you need only dial (the verb hasn’t changed, even though telephones no longer have a dial) the seven-digit exchange code and number; otherwise, you must dial the complete ten-digit number, often with a prefix.
Our exercise today asks you to validate a telephone number, as if written on an input form. Telephone numbers can be written as ten digits, or with dashes, spaces, or dots between the three segments, or with the area code parenthesized; both the area code and any white space between segments are optional. Thus, all of the following are valid telephone numbers: 1234567890, 123-456-7890, 123.456.7890, (123)456-7890, (123) 456-7890 (note the white space following the area code), and 456-7890. The following are not valid telephone numbers: 123-45-6789, 123:4567890, and 123/456-7890.
Your task is to write a phone number validator that follows the rules given above; your function should either return a valid telephone number or an indication that the input is invalid. Be sure to write a proper test suite. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
http://pastebin.com/iNVSP0zu
the easy way out :-)
Your posts are extremely useful!
But… why LISP
@geirskjootskift: The task requires you to return the number if it is valid, not just a true or false.
@Ajay: Thank you. It’s Scheme, not Lisp. And because I want to, and because Scheme gives me options not (easily) available in C or Java or Python; Scheme gives me things like garbage collection and big integers for free, and in what other language could I add list comprehensions and pattern matching to the standard library, and write generators and streams and other little goodies?
Clojure solution using regexp like geirskjootskift,
– use two regexp, deliberately permissive on numbers of seps
– use regexp groups to extract a normalized phone number.
Some tests with valid and invalid entries
Here is my solution (also using Regex…)
import re
import itertools
def isTelephone(n):
regex=re.compile(“([0-9]{10})|([0-9]{3}[-]{1}[0-9]{3}[-]{1}[0-9]{4})|([0-9]{3}[.]{1}[0-9]{3}[.]{1}[0-9]{4})|([\(]{1}[0-9]{3}[\)][ ]{1}[0-9]{3}[-]{1}[0-9]{4})|([0-9]{3}[-]{1}[0-9]{4})”)
chain = itertools.chain(*regex.findall(n))
if n in list(chain):
return n
else:
return False
def test():
test_numbers=[‘1234567890’,
‘123-456-7890’,
‘123.456.7890’,
‘(123) 456-7890’,
‘456-7890’,
‘123-45-6789’,
‘123 4567890’,
‘123/456-7890’]
for num in test_numbers:
print(isTelephone(num))
test()
Here is my solution using python and regex
Ok.. returned on normalized form. Still don’t see no reason to implement a parser “by hand” :-) I also prefer not putting all patterns in as few regexps as possible. Readability for the win.
VALID_PHONE_PATTERNS = [
"^(\d{10})$",
"^(\d{3})\-(\d{3})\-(\d{4})$",
"^(\d{3})\.(\d{3})\.(\d{4})$",
"^\((\d{3})\)\s?(\d{3})\-(\d{4})$",
"^(\d{3})\-(\d{4})$"]
def validate_phone_number(phn):
for pattern in VALID_PHONE_PATTERNS:
res = compile(pattern).findall(phn)
if res:
return "".join(res[0])
return None
I see that reading : https://programmingpraxis.com/contents/howto-posting-source-code/ didn’t do me no good :-D
http://pastebin.com/7JJKhd05
.. readability again
Your rules state that 123/456-7890 is not valid; while it is the least common use, it is frequently used by people. If I were writing code I would use it.
I would normally use a list of regex’s like some of the previous solutions. I used one big regular expression; however, because having two problems is better than having just one problem (see http://regex.info/blog/2006-09-15/247).
normalize() returns a tuple with the areacode, exchange, and number, or raises a ValueError if the input is not a valid phone number. The areacode is None if one was not provided.
@praxis, I don’t know Scheme, but was wondering how your code would handle the last 4 invalid test cases I added?
Figured it was easier to break it into 2 options, as flagging the case (123-456-7890 is a bit annoying. Also assumes you can mix and match – and ., so 123-456.7890 is ok.
[…] is a solution to a programmingpraxis exercise -validating telephone […]
OK, initially missed a couple of requirements, so this is iteration 3 of my solution – over time and over budget ;-) But at least you get the unit tests.
One more thing – I’ve just read the suggested solution and liked the trick with working backwards.
My regex-based version above was clearly a tounge-in-cheek solution. Here is a more useful solution.
It uses a regular expression to group the input string into digits and non-digits. The non-digits are normalized to form a punctuation string, which is compared with a set of valid punctuation strings. Other valid punctuation, e.g., 123/456-7890, can easily be added by adding the punctuation string, e.g., ” /-“, to validpunctuation.
Here is my solution using python:
Note that I’m still a n00b in Phython so I know there are some semantic bugs, e.g. phones like “(123-456 7890” or “123)456 7890” will match
@Diego Giuliani you should avoid using str as a variable because str is actually a built-in function see here -> http://docs.python.org/library/functions.html#str