Fastest method for testing a fixed phone number pa

2019-02-14 00:00发布

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.

6条回答
仙女界的扛把子
2楼-- · 2019-02-14 00:14

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);
}
查看更多
叛逆
3楼-- · 2019-02-14 00:18

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);
查看更多
别忘想泡老子
4楼-- · 2019-02-14 00:19

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;
}
查看更多
男人必须洒脱
5楼-- · 2019-02-14 00:26
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) != '-');
}
查看更多
闹够了就滚
6楼-- · 2019-02-14 00:30

you can use regex for that:

if(/^[0-9]{3}-[0-9]{3}-[0-9]{4}$/.test('123-456-7890'))
    //ok
else
    //not ok
查看更多
Fickle 薄情
7楼-- · 2019-02-14 00:32

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)

查看更多
登录 后发表回答