I’m working on my FreeCodeCamp JavaScript Algorithms and Data Structures certificate. I’ve used regular expressions quite a bit in various projects, but I’ve never really felt confident about them, you know? When I read this problem, though, I knew I was going to need to develop some mastery, because there’s not a better way to handle this than a well-crafted regex.
Return
true
if the passed string looks like a valid US phone number.The user may fill out the form field any way they choose as long as it has the format of a valid US number. The following are examples of valid formats for US numbers (refer to the tests below for other variants):
555-555-5555
(555)555-5555
(555) 555-5555
555 555 5555
5555555555
1 555 555 5555For this challenge you will be presented with a string such as
800-692-7753
or8oo-six427676;laskdjf
. Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code is provided, you must confirm that the country code is1
. Returntrue
if the string is a valid US phone number; otherwise returnfalse
.
First Draft
My first draft wasn’t too bad – it passed more than half the tests anyway.
function telephoneCheck(str) { let telRegex = /1?[ (-]?\d{3}[ )-]?\d{3}[ -]?\d{4}/ return telRegex.test(str); } telephoneCheck("555-555-5555");
Let’s break down my thought process here and then get into the failed tests.
-
- We check for the country code using
1?
. Using the question mark means that 1 can appear or not; either will pass. - We have
[ (-]?
. This checks if either a space, opening parenthesis, or dash appears; again, we use the question mark, because these may or may not appear in this position. Spoiler: this is what caused our first failed test, which is:telephoneCheck("1 (555) 555-5555") should return true
. See if you can figure out why and we’ll revisit on our second draft. - We check for any digit appearing exactly three times by using
\d{3}
. - We repeat step two, except with a closing parenthesis in this character set rather than an opening:
[ )-]?
. - We repeat step three with
\d{3}
. - We use another character set, this time with either a space or a dash:
[ -]?
. Again, we include the question mark for when neither appears. - We check for four consecutive digits with
\d{4}
.
Second Draft
Have you been thinking about the failed test I shared above? There’s a space and parenthesis on either side of the area code here, so we’ll need to make a small change to our pattern. We’ll replace the ? character with a * character, which matches zero or more appearances of a character in a set rather than just zero or one.
I’m also going to add a ^ character to the beginning of my regex and a $ character to the end so that extra characters on either side will be caught and rejected for the garbage they are. Here are a couple failed tests that prompted me to do this:
telephoneCheck("-1 (757) 622-7382") should return false telephoneCheck("(6054756961)") should return false
I’ve already noticed that this won’t pass every test, but I like to run my revised functions frequently to keep up with failed ones.
function telephoneCheck(str) { let telRegex = /^1?[ (-]*\d{3}[ )-]*\d{3}[ -]?\d{4}$/ return telRegex.test(str); } telephoneCheck("555-555-5555");
Third Draft
Now we’re really getting somewhere, and this is an example of why I like to check a function’s results even when I know it won’t be perfect: we only have three remaining failed tests at this point.
telephoneCheck("1 555)555-5555") should return false. telephoneCheck("555)-555-5555") should return false. telephoneCheck("(555-555-5555") should return false.
I’m not going to lie. I look at those failed tests and I really want to just insert a simple
if
statement to check that both sides of the parentheses are complete. But I’m determined to do this with regular expressions, and that’s what I’m going to do.So what if we were to adjust things like so?
function telephoneCheck(str) { let telRegex = /^1?[ -]*(\d{3}|\(\d{3}\))[ -]*\d{3}[ -]?\d{4}$/ return telRegex.test(str); } telephoneCheck("555-555-5555");
This passes all the tests! Let’s cover what I changed:
[ (-]* -> [ -]* [ )-]* -> [ -]*
I removed the parentheses from these groups and instead used the alternation operator to match either three digits or three digits surrounded by parentheses:
(\d{3}|\(\d{3}\))
Note that this did require escaping the matched parentheses within the outer set of parentheses.
And there it is. A regular expression that does what it needs. Happy coding.
- We check for the country code using