2

I have the following regex for phone number validation

function validatePhonenumber(phoneNum) {
    var regex = /^[1-9]{3}[-\s\.]{0,1}[0-9]{3}[-\s\.]{0,1}[0-9]{4}$/;
    return regex.test(phoneNum);
}

However, I would liek to make sure it doesn;t pass for different separators such as in 111-222.3333

Any ideas how to make sure the separators are the same always?

  • http://stackoverflow.com/questions/123559/a-comprehensive-regex-for-phone-number-validation?rq=1 - the accepted answer here might be a better approach. However, you might have to use 3 different regexps, one for each separator, and just allow matching any one of the expressions. Otherwise, i don't think there's a clear (or even _any_) way of doing this with javascript regexps. – mechalynx Jul 12 '14 at 18:59
  • your regex pattern is working fine. – Braj Jul 12 '14 at 19:03
  • 1
    Put the first separator set in a capturing group, and use a back reference for the second separator `/^[1-9]{3}([-\s\.]){0,1}[0-9]{3}\1{0,1}[0-9]{4}$/` – cookie monster Jul 12 '14 at 19:08
  • @cookiemonster post it as answer. – Braj Jul 12 '14 at 19:13
  • @Braj, user: The part I'm unsure of is if it should pass if there's a second separator, but no first separator. As it is, it'll fail that scenario, though the opposite (first but no second) will pass. – cookie monster Jul 12 '14 at 19:20

3 Answers3

2

Just make sure beforehand that there is at most one kind of separator, then pass the string through the regex as you were doing.

function validatePhonenumber(phoneNum) {
    var separators = extractSeparators(phoneNum);
    if(separators.length > 1) return false;

    var regex = /^[1-9]{3}[-\s\.]{0,1}[0-9]{3}[-\s\.]{0,1}[0-9]{3}$/;
    return regex.test(phoneNum);
}

function extractSeparators(str){
    // Return an array with all the distinct chars
    // that are present in the passed string
    // and are not numeric (0-9)
}
abl
  • 5,970
  • 4
  • 25
  • 44
2

You can use the following regex instead:

\d{3}([-\s\.])?\d{3}\1?\d{4}

Here is a working example:

http://regex101.com/r/nN9nT7/1

Regular expression visualization

As result it will match the following result:

111-222-3333   --> ok
111.222.3333   --> ok
111 222 3333   --> ok
111-222.3333
111.222-3333
111-222 3333
111 222-3333

EDIT: after Alan Moore's suggestion:

Also matches 111-2223333. That's because you made the \1 optional, which isn't necessary. One of JavaScript's stranger quirks is that a backreference to a group that did not participate in the match, succeeds anyway. So if there's no first separator, ([-\s.])? succeeds because the ? made it optional, and \1 succeeds because it's JavaScript. But I would have used ([-\s.]?) to capture the first separator (which might be nothing), and \1 to match the same thing again. This works in any flavor, including JavaScript.

We can improve the regex to:

^\d{3}([-\s\.]?)\d{3}\1\d{4}$
Community
  • 1
  • 1
Federico Piazza
  • 30,085
  • 15
  • 87
  • 123
  • Also matches `111-2223333`. That's because you made the `\1` optional, which isn't necessary. One of JavaScript's stranger quirks is that a backreference to a group that did not participate in the match, succeeds anyway. So if there's no first separator, `([-\s\.])?` succeeds because the `?` made it optional, and `\1` succeeds because it's JavaScript. But I would have used `([-\s.]?)` to capture the first separator (which might be nothing), and `\1` to match the same thing again. This works in any flavor, including JavaScript. – Alan Moore Jul 13 '14 at 00:25
  • So, are you going to fix it? I can't upvote an answer that doesn't work. :P You can put the anchors (`^` and `$`) back in while you're at it; we're trying to *validate* the string, not search for it. – Alan Moore Jul 13 '14 at 14:06
  • @AlanMoore sorry had no time. It's updated now, thanks to help improving the answer – Federico Piazza Jul 13 '14 at 17:06
0

You'll need at least two passes to keep this maintainable and extensible.

JS' RegEx doesn't allow for creating variables for use later in the RegEx, if you want to support older browsers.
If you are only supporting modern browsers, Fede's answer is just fine...

As such, with ghetto-support, you aren't going to be able to reliably check that one separator is the same value every time, without writing a really, really, really, stupidly-long RegEx, using | to basically write out the RegEx 3 times.

A better way might be to grab all of the separators, and use a reduction or a filter to check that they all have the same value.

var userEnteredNumber = "999.231 3055";

var validNumber = numRegEx.test(userEnteredNumber);

var separators = userEnteredNumber.replace(/\d+/g, "").split("");

var firstSeparator = separators[0];
var uniformSeparators = separators.every(function (separator) { return separator === firstSeparator; });

if (!uniformSeparators) { /* also not valid */ }

You could make that a little neater, using closures and some applied functions, but that's the idea.

Alternatively, here's the big, ugly RegEx that would allow you to test exactly what the user entered.

var separatorTest = /^([0-9]{3}\.[0-9]{3}\.[0-9]{3,4})|([0-9]{3}-[0-9]{3}-[0-9]{3,4})|([0-9]{3} [0-9]{3} [0-9]{3,4})|([0-9]{9,10})$/;

Notice I had to include the exact same number-test three times, wrap each one in parens (to be treated as a single group), and then separate each group with an | to check each group, like an if, else if, else... ...and then plug in a separate special case for having no separator at all...

...not pretty. I'm also not using \d, just because it's easy to forget that - and . are both accepted "digit"s, when trying to maintain one of these abominations.

Now, a word or two of warning:

  1. People are liable to enter all kinds of crap; if this is for a commercial site, it's likely better to just strip separators entirely and validate the number is the right size, and conforms to some specifics (eg: doesn't start with /^555555/).

  2. If not given any instruction about number format, people will happily use either no separator or a formal number, like (555) 555-5555 (or +1 (555) 555-5555 for the really pedantic), which is obviously going to fail hard, in this system (see point #1).

  3. Be prepared to trim what you get, before validating.

  4. Depending on your country/region/etc laws about data-security and consumer-vs-transaction record-keeping (again, may or may not be more important in a commercial setting), it's likely better to store both a "user-given" ugly number, and a system-usable number, which you either clean on the back-end, or submit along with the user-entered text.

  5. From a user-interaction perspective, either forcing the number to conform, explicitly (placeholders showing them xxx-xxx-xxxx right above the input, in bold), or accepting any text, and prepping it yourself, is going to be 1000x better than accepting certain forms, but not bothering to tell the user up-front, and instead telling them what they did was wrong, after they try.
    It's not cool for relationships; it's equally not cool, here.

  6. You've got 9-digit and 10-digit numbers, so if you're trying for an international solution, be prepared to deal with all international separators (, \.\-\(\)\+) etc... again, why stripping is more useful, because THAT RegEx would be insane.

Norguard
  • 26,167
  • 5
  • 41
  • 49
  • What do you mean by "older browsers"? I think it's safe to assume regexes with capturing groups are available. You make some good points about user experience and security, but the question was about making sure the separators are the same, and capturing groups can handle that. – Alan Moore Jul 13 '14 at 00:41
  • @AlanMoore What I mean to say is that old JScript implementations of RegEx were not solid in IE4/5/5.5... Perhaps 6. I can't say for certain, because Microsoft has done an abysmal job of documenting what does and does not work when/where, in which browser. Yes, technically, these are not "old" browsers, they are ***ancient*** browsers, but keep in mind that the last company I worked for was doing this kind of validation, commercially, and only officially dropped IE<7 support last year. That's what I mean by "supporting old browsers". It's also why "commercial" makes a difference. – Norguard Jul 13 '14 at 11:41