Question

So, the challenge is that we are trying to detect if a string matches a fixed phone number pattern, this is a simple string pattern.

The pattern is:

ddd-ddd-dddd

Where "d "represents a decimal digit and the minus symbol represents itself, "-"

The patterns that are currently used for testing are, but can be increased if it is felt that there are not enough patterns to debunk an incorrect format.

"012-345-6789"
"0124-345-6789"
"012-3456-6789"
"012-345-67890"
"01a-345-6789"
"012-34B-6789"
"012-345-678C"
"012"

The goal , the answer that I seek, is to find the method that executes the fastest to return a boolean where true means that the pattern is good and false means that the pattern is bad.

Here is my current solution

function matchesPattern(pattern) {
    if (pattern.length !== 12) {
        return false;
    }

    var i = 0,
        code;

    while (i < 12) {
        code = pattern.charCodeAt(i);

        if (i > 8 || i % 4 !== 3) {
            if (code < 48 || code > 57) {
                return false;
            }
        } else if (code !== 45) {
            return false;
        }

        i += 1;
    }

    return true;
}

It is available on jsfiddle along with the test patterns

I have a jsperf created where I will add further suggested method so that the execution speeds of the methods can be compared to determine which is fastest

Your method can be any valid javascript code that will execute in the a browser, you can use ECMA5 and target modern browsers if you so wish, or use cross-browser standards, the answer will not be deemed incorrect if it does not run on IE6 for example. You may also use any 3rd party libraries that you wish, i.e. jquery, lodash, underscore, etc etc. The final requirement is that the code must not fail to execute on Chrome v25 or Firefox v20

I anything is unclear then please feel free to leave a comment and I will update my question to clarify.

Answers that differ by only micro-optimisations count

Please don't change your answer if it working and has been added to the performance chart. You can submit more than 1 answer.

Update: Ok a week has passed and now it is time to announce the answer that I will choose.

What has been learnt from this exercise?

It would seem that regexs are comparatively slow, although fast enough for most tasks, when compared to a hand built javascript routine. (at least for small string patterns)

There was no solution using any 3rd party library, jquery, undescore etc, nothing. Not so much of a surprise, but I though that someone may have tried.

Unrolled loops still appear to be king. Many say that it is not necessary these days as the browsers are so advanced, but this test still showed them to be king of the pile.

I'd like to thank all those that engaged in this question, and especially to those that actually submitted code for testing.

Was it helpful?

Solution

even faster than before:

function tecjam5(pattern) {
    var c;
    return !(pattern.length != 12 ||
    !(((c=pattern.charCodeAt(2))>>3) == 6 || (c>>1) == 28) ||
    !(((c=pattern.charCodeAt(4))>>3) == 6 || (c>>1) == 28) ||
    !(((c=pattern.charCodeAt(11))>>1) == 28 || (c>>3) == 6) ||
    !(((c=pattern.charCodeAt(0))>>3) == 6 || (c>>1) == 28) ||
    !(((c=pattern.charCodeAt(1))>>3) == 6 || (c>>1) == 28) ||
    !(((c=pattern.charCodeAt(5))>>3) == 6 || (c>>1) == 28) ||
    !(((c=pattern.charCodeAt(6))>>3) == 6 || (c>>1) == 28) ||
    !(((c=pattern.charCodeAt(8))>>3) == 6 || (c>>1) == 28) ||
    !(((c=pattern.charCodeAt(9))>>3) == 6 || (c>>1) == 28) ||
    !(((c=pattern.charCodeAt(10))>>1) == 28 || (c>>3) == 6) ||
    pattern.charAt(3) != '-' || pattern.charAt(7) != '-');
}

(short: every number < 8 only need compared once)

OTHER TIPS

function whyNotBeSilly(pattern) {
  return !(pattern.length !== 12 ||
           (code = pattern.charCodeAt(0)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(1)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(2)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(4)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(5)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(6)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(8)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(9)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(10)) < 48 || code > 57 ||
           (code = pattern.charCodeAt(11)) < 48 || code > 57 ||
           pattern.charAt(3) != '-' || pattern.charAt(7) != '-');
}

you can use regex for that:

if(/^[0-9]{3}-[0-9]{3}-[0-9]{4}$/.test('123-456-7890'))
    //ok
else
    //not ok

A slight variation of one of the other answers, but I believe the built-in character class should be slightly faster than a custom one:

return /^\d{3}-\d{3}-\d{4}$/.test(phoneNumber);

Declaring a regex object pre-compiles it for any future use. Since you are looping through several test strings, it should perform better to instantiate the object outside the function first:

var rex = /^\d{3}-\d{3}-\d{4}$/;

Then the function would be:

function matchesPattern(pattern) {
    return rex.test(pattern);
}

very fast:

   function tecjam3(pattern) {
  if (pattern.length !== 12) {
    return false;
  }

  code = pattern.charCodeAt(0);
  if (code < 48 || code > 57) return false;
  code = pattern.charCodeAt(1);
  if (code < 48 || code > 57) return false;
  code = pattern.charCodeAt(2);
  if (code < 48 || code > 57) return false;

  code = pattern.charCodeAt(4);
  if (code < 48 || code > 57) return false;
  code = pattern.charCodeAt(5);
  if (code < 48 || code > 57) return false;
  code = pattern.charCodeAt(6);
  if (code < 48 || code > 57) return false;

  code = pattern.charCodeAt(8);
  if (code < 48 || code > 57) return false;
  code = pattern.charCodeAt(9);
  if (code < 48 || code > 57) return false;
  code = pattern.charCodeAt(10);
  if (code < 48 || code > 57) return false;
  code = pattern.charCodeAt(11);
  if (code < 48 || code > 57) return false;

  if (pattern.charAt(3) != '-' || pattern.charAt(7) != '-') return false;

  return true;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top