This is a solution to a programmingpraxis exercise -validating telephone numbers.

If someone is new to programming the “test first” approach may come as a nuisance. At the first glance it introduces an unnecessary step into the work flowchart. You, a flawless programmer, are sure to get everything perfect the first time. If it compiles, it works. Right?

Not really. Getting a call about your code being a cause of a serious problem in a “production environment” is a humbling experience. It’s a lesson learned. Well, there are things you can do to avoid mistakes. If you write unit tests first, before starting work on your new features, most if not all of testsĀ  shoould fail when you run them. Once you start adding new code, new features, more and more red lights are replaced with green ones. If the unit tests cover the functionality well enough, your code is ready when all the tests pass. I may not be the best authority on testing but at least I learned that technique directly from Dean Wampler.

Enough rambling about obvious things. For the exercise I simply wrote a regular expression. I hope it is completely correct, but at least the unit tests all pass. ;-)

import unittest
import re

tele_re = re.compile(r"(\(?[0-9]{3}\)?)?[- \.]?[0-9]{3}[- \.]?[0-9]{4}")

def is_tele(s):
    return tele_re.match(s)

class TestTelephoneNumbers(unittest.TestCase):
    def setUp(self):
        self.good = [ "1234567890", "123-456-7890", "123.456.7890", "(123)456-7890", "(123) 456-7890", "456-7890" ]
        self.bad = [ "123-45-6789", "123:4567890", "123/456-7890" ]
    def test_good(self):
        for tele_num in self.good:
            self.assertTrue(is_tele(tele_num), tele_num)
    def test_bad(self):
        for tele_num in self.bad:
            self.assertFalse(is_tele(tele_num), tele_num)

if __name__ == '__main__':
    unittest.main()

Update: I did not read the exercise carefully. No amount of unit tests helps if you misrepresent the problem you are trying to solve. The solution was expected to return the valid phone number. So here is version 2.

import unittest
import re

tele_re = re.compile(r"(\(?[0-9]{3}\)?)?[- \.]?[0-9]{3}[- \.]?[0-9]{4}")

def is_tele(s):
    return tele_re.match(s)

def tele(s):
    if is_tele(s):
        return "".join([c for c in s if '0' <= c <= '9' ])

class TestTelephoneNumbers(unittest.TestCase):
    def setUp(self):
        self.good = [ "1234567890", "123-456-7890", "123.456.7890", "(123)456-7890", "(123) 456-7890", "456-7890" ]
        self.bad = [ "123-45-6789", "123:4567890", "123/456-7890" ]
    def test_good(self):
        for tele_num in self.good:
            self.assertTrue(is_tele(tele_num), tele_num)
    def test_bad(self):
        for tele_num in self.bad:
            self.assertFalse(is_tele(tele_num), tele_num)
    def test_extract(self):
        for tele_num in self.good[0:-1]:
            self.assertEqual(tele(tele_num), self.good[0], msg="%s extract failed" % tele_num)
        self.assertEqual(tele(self.good[-1]), "4567890", msg="%s extract failed" % self.good[-1])
       

if __name__ == '__main__':
    unittest.main()

Another update. It seems that it's more acceptable if the parens match. Iteration 3!

import unittest
import re

tele_re = re.compile(r"((\([0-9]{3}\))|([0-9]{3}))?[- \.]?[0-9]{3}[- \.]?[0-9]{4}")

def is_tele(s):
    return tele_re.match(s)

def tele(s):
    if is_tele(s):
        return "".join([c for c in s if '0' <= c <= '9' ])

class TestTelephoneNumbers(unittest.TestCase):
    def setUp(self):
        self.good = [ "1234567890", "123-456-7890", "123.456.7890", "(123)456-7890", "(123) 456-7890", "456-7890" ]
        self.bad = [ "123-45-6789", "123:4567890", "123/456-7890", "(123 456 7890", "123)456 7890", "(456)7890" ]
    def test_good(self):
        for tele_num in self.good:
            self.assertTrue(is_tele(tele_num), tele_num)
    def test_bad(self):
        for tele_num in self.bad:
            self.assertFalse(is_tele(tele_num), tele_num)
    def test_extract(self):
        for tele_num in self.good[0:-1]:
            self.assertEqual(tele(tele_num), self.good[0], msg="%s extract failed" % tele_num)
        self.assertEqual(tele(self.good[-1]), "4567890", msg="%s extract failed" % self.good[-1])
       

if __name__ == '__main__':
    unittest.main()
About these ads