电话号码正则表达式所有格式

3
我正在开发一个表达式来验证所有可能的电话号码格式。我完成了50%的工作,但它没有通过* . - whitespace来验证可接受的字符。
以下是规则:
  • 可以包含括号,例如 (55)。
  • 可以包含或不包含'+'字符,例如(+52)。
  • 括号内可以包含2或3个数字,例如 (+555) 或 (+55)。
  • 在关闭括号和下一个数字之间可以包含空格,例如 (55) 44332211。
  • 紧挨着括号的连续数字必须是6或8个数字,例如 (55)443322 或 (55)44332211。
  • 与括号相邻的连续数字可以包含空格、破折号、星号或冒号,例如(55)44-33-22-11 或 (55)44 33 22 11 或 (55)44*33*22*11 或 (55)44.33.22.11。
  • 与括号相邻的连续数字可以分为2、3或4个数字的组,例如(55)5544-3322 或 (55)55 44 33 22 或 (555)444*333。
  • 号码格式可以连续出现8、10或12个数字,例如55443322 或 5544332211 或 554433221100。
这是正则表达式:
[\(]?[\+]?(\d{2}|\d{3})[\)]?[\s]?((\d{6}|\d{8})|(\d{3}[\*\.\-\s]){3}|(\d{2}[\*\.\-\s]){4}|(\d{4}[\*\.\-\s]){2})|\d{8}|\d{10}|\d{12}

这是一个正则表达式的地图

enter image description here

我做错了什么?我留下一个脚本示例,我正在为Python编写正则表达式,我不知道是否需要在JS中进行更改。

$(function(){

  $('ul li').each(function(){
    let number = $(this).text();
    let regex = /^[\(]?[\+]?(\d{2}|\d{3})[\)]?[\s]?((\d{6}|\d{8})|(\d{3}[\*\.\-\s]){3}|(\d{2}[\*\.\-\s]){4}|(\d{4}[\*\.\-\s]){2})|\d{8}|\d{10}|\d{12}$/;
    let res = regex.test( number );
    $(this).text( $(this).text() + ' is: ' + res);
  });

})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Telephone numbers
<ul>
  <li>test</li>
  <li>(55)test</li>
  <li>(55)333-test</li>
  <li>(55)test 22</li>
  <li>554433221100</li>
  <li>5544332211</li>
  <li>55443322</li>
  <li>(55)443322</li>
  <li>(55)44332211</li>
  <li>(+55)443322</li>
  <li>(+55)44332211</li>
  <li>(55)4433*2211</li>
  <li>(55)444.333</li>
  <li>(55)44-33-22-11</li>
  <li>(55)4433-2211</li>
  <li>(+55)443 322</li>
</ul>


1
这是否意味着你的所有测试用例都应该返回 true - Wiktor Stribiżew
1
只有在规则中指定的情况下才允许使用,例如(55)测试是不允许的,但是55-44-33-22-11是可以的(但它并不起作用:())。 - Alberto Siurob
1
@AlbertoSiurob,你的规则中有很多漏洞。这些号码是否被允许:(55)123-4567555-123-456755-1234-56+55123456551-234-567(其中55是国际代码)? - ctwheels
1
这是一个例子,它可以以(32)55开头,我的区号是。 - Alberto Siurob
1
@AlbertoSiurob 是的,但这些示例应该有什么结果?还有5555*5555*555555 12-12-1255 123-123呢? - ctwheels
获取正确的电话号码正则表达式是一项棘手的任务,我建议阅读Jan Goyvaerts和Steven Levithan(2009)的《正则表达式手册》(请参见第3.5节、第4.2节和第4.3节)。 - gregory
3个回答

3

您可以使用

^(?:\d{8}(?:\d{2}(?:\d{2})?)?|\(\+?\d{2,3}\)\s?(?:\d{4}[\s*.-]?\d{4}|\d{3}[\s*.-]?\d{3}|\d{2}([\s*.-]?)\d{2}\1\d{2}(?:\1\d{2})?))$

请参见正则表达式演示.

细节

  • ^ - 字符串开头
  • (?: - 开始一个外部分组结构:
    • \d{8} - 8个数字
    • (?:\d{2}(?:\d{2})?)? - 可选的两个数字,后跟可选的两位数字子字符串(因此可以匹配8、10或12位数字字符串)
  • | - 或

    • \( - 一个 (
    • \+? - 1个或0个加号
    • \d{2,3} - 2或3个数字
    • \) - 一个 ) 字符
    • \s? - 1个或0个空格
    • (?: - 一个分组:
      • \d{4} - 4个数字
      • [\s*.-]? - 一个空格、*.-,可选出现
      • \d{4} - 4个数字
    • | - 或
      • \d{3}[\s*.-]?\d{3} - 3个数字,一个分隔符字符,3个数字
    • | - 或

      • \d{2}([\s*.-]?)\d{2}\1\d{2}(?:\1\d{2})?: 2个数字,一个捕获到组1的分隔符字符,2个数字,与组1中相同的分隔符,2个数字,以及可选的与组1中相同的分隔符字符和两个数字的序列
    • ) - 结束内部分组。

  • ) - 结束外部分组
  • $ - 字符串结尾。

2
美丽、令人敬畏和详细。谢谢您,先生。 - Alberto Siurob
1
我不想再开一个新的线程,只是为了结束这个话题,你能告诉我当号码是+55 52 4433 2211或者5522 3030时的验证方式吗? - Alberto Siurob
2
你是一个怪物!一辆满载啤酒的卡车正驶向你的房子。谢谢。 - Alberto Siurob

0

被接受的答案有很多缺陷:

  • \s 不仅匹配空格字符,还包括\r和\n。

    +11 1111
    1111
    #这个匹配
    
  • 数字的最小位数为8,最大位数为12,但这些数字与国际前缀数字无关:

    (+39)333 333 # 6位数字:这个匹配但不是有效的  
    (+39)3333 3333 3333 # 12位数字:这个是有效的但不匹配
    
  • 国际前缀只在括号内匹配

    +39 3475 4087 18 # 这个是有效的但不匹配
    
  • 正则表达式并不是毫无道理的琐碎、冗长、复杂和有错误。

我制作了这个来克服那些缺陷并改进它:

^(?:((\+?\d{2,3})|(\(\+?\d{2,3}\))) ?)?(((\d{2}[\ \-\.]?){3,5}\d{2})|((\d{3}[\ \-\.]?){2}\d{4}))$

通过接受的答案中提供的良好解释,理解这个应该相对容易。

这是一个实时演示


0
另一个可能的解决方案(可能更简单)是在源头验证电话号码,然后只允许服务器端使用这种格式。

(function(){
  "use strict";
  var removeNonPhoneNumber = /\D/g;

  function formatPhoneNumber(ownSection, restOfIt){
    var newOwnSection = ownSection.replace(removeNonPhoneNumber, "");
    var newRestOfIt = restOfIt.replace(removeNonPhoneNumber, "");
    var totalLength = newOwnSection.length + restOfIt.length |0;

    var i=0, res="";
    if (totalLength > 10) {
      // includes country code
      for (; i < (totalLength - 10|0) && i < newOwnSection.length; i=i+1|0)
        res += newOwnSection.charAt(i);
      res += '-';
    }
    if (totalLength > 7) {
      // includes area code
      for (; i < (totalLength - 7|0) && i < newOwnSection.length; i=i+1|0)
        res += newOwnSection.charAt(i);
      res += '-';
    }
    if (totalLength > 4) {
      // includes local code
      for (; i < (totalLength - 4|0) && i < newOwnSection.length; i=i+1|0)
        res += newOwnSection.charAt(i);
      res += '-';
    }
    for (; i < totalLength && i < newOwnSection.length; i=i+1|0)
      res += newOwnSection.charAt(i);
    return res;
  }
  function autoStretch(evt){
    var target = evt && evt.target;
    if (!target) return;
    if (
      target.getAttribute("type") === "tel" && (
        // If selectionStart is supported OR the user is deselecting
          // the input, then validate
        typeof target.selectionStart === "number" ||
        evt.type === "blur"
      )
    ) {
      // forceful tel validation. It normalizes the number to be pretty
      var valueNow = target.value;
      var sStart=target.selectionStart|0, sEnd=target.selectionEnd|0;

      var newValue = formatPhoneNumber(valueNow, "");
      if (valueNow !== newValue) {
        target.value = newValue;

        // now properly shift around the cursor positions:
        if(typeof target.selectionStart==="number") 
          target.selectionStart = formatPhoneNumber(
            valueNow.substring(0, sStart), valueNow.substring(sStart)
          ).length|0;
        if(typeof target.selectionEnd==="number") 
          target.selectionEnd = formatPhoneNumber(
            valueNow.substring(0, sEnd), valueNow.substring(sEnd)
          ).length|0;
      }
    }
    target.style.width = '';
    target.style.width = target.scrollWidth + 'px';
  }

  var teleInputs = document.getElementsByClassName("prevent-invalid-telephone");
  for (var i=0, hookOptions={"passive":1}; i<teleInputs.length; i=i+1|0) {
    teleInputs[i].addEventListener("input", autoStretch, hookOptions);
    teleInputs[i].addEventListener("change", autoStretch, false);//for IE
  }
})();
Enter your telephone here: <input type="tel" autocomplete="tel-area-code" pattern="([0-9]+-)?[0-9]{3}-[0-9]{3}-[0-9]{4}" aria-label="Your telephone number" class="prevent-invalid-telephone"/>

上面的代码片段看起来可能很长,但放心,经过缩小后只有1008个字节(应用zopfli gzip后仅为486个字节)。

!function(){"use strict";function h(c,b){var d=c.replace(/\D/g,"")
b.replace(/\D/g,"");var e=d.length+b.length|0,a=0,f=""
if(10<e){for(;a<(e-10|0)&&a<d.length;a=a+1|0)f+=d.charAt(a)
f+="-"}if(7<e){for(;a<(e-7|0)&&a<d.length;a=a+1|0)f+=d.charAt(a)
f+="-"}if(4<e){for(;a<(e-4|0)&&a<d.length;a=a+1|0)f+=d.charAt(a)
f+="-"}for(;a<e&&a<d.length;a=a+1|0)f+=d.charAt(a);return f}function
l(c){var b=c&&c.target;if(b){if("tel"===b.getAttribute("type")&&("number"==typeof
b.selectionStart||"blur"===c.type)){c=b.value;var
d=b.selectionStart|0,e=b.selectionEnd|0,a=h(c,"")
c!==a&&(b.value=a,"number"==typeof b.selectionStart&&(b.selectionStart=h(
c.substring(0,d),c.substring(d)).length|0),"number"==typeof
b.selectionEnd&&(b.selectionEnd=h(c.substring(0,e),c.substring(e)).length|0))}
b.style.width="";b.style.width=b.scrollWidth+"px"}}for(var
k=document.getElementsByClassName("prevent-invalid-telephone"),g=0;g<k.length;g=g+1|0)
k[g].addEventListener("input",l,{passive:1}),k[g].addEventListener("change",l,!1)}();
Enter your telephone here: <input type="tel" autocomplete="tel-area-code" pattern="([0-9]+-)?[0-9]{3}-[0-9]{3}-[0-9]{4}" aria-label="Your telephone number" class="prevent-invalid-telephone"/>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接