美文网首页web前端java程序员
验证手机号码格式的正则表达式编写思路详解

验证手机号码格式的正则表达式编写思路详解

作者: 梦蓝蓝的 | 来源:发表于2016-12-08 17:22 被阅读469次

    一、获取中国目前三大运营商的手机号码段
    手机号码段链接http://www.gouhaowang.com/xuanhao

    手机号段.png

    如上图我们可以根据不同运营商的号码段来编写正则,也可以进行统一校验的编写,我这边主要是编写统一校验的。

    二、编写思路
    1、为了得到号码段的规律,我们可以把它们先进行排序一下,排序代码如下:

     int[] phoneHead={134,135,136,137,138,139,182,183,187,188,152,157,158,159,150,147,184,151,178,1705  
                       ,130,131,132,155,156,186,145,185,1709,1707,1708,176  
                       ,133,153,180,181,189,177,1700,173};  
                       
                     Arrays.sort(phoneHead);  
                     for(int head:phoneHead){  
                      System.out.print(head+"\t");  
                     }  
    

    排序结果:

    22.png

    2、由上面的排序结果可以看出,规律还是挺明显的,首先我们来看一下,
    13开头:130 131132 133134 135136 137138 139 对应正则为:(13[0-9]\d{8})

    14开头:145 147 对应正则为:(14[57]\d{8})

    15开头:150 151152 153155 156157 158159 对应正则为:(15[0-35-9]\d{8})

    17开头:173 176177 178 对应正则 为:(17[36-8]\d{8})

    18开头:180 181182 183184 185186 187188 189对应正则为:(18[0-9]\d{8})

    170开头:1700 1705 1707 1708 1709 对应正则为:(170[057-9]\d{7})
    3、把上面的正则用或符号(|)拼在一起,就是一个完整的校验手机号的正则表达式了,如下
    (13[0-9]\d{8})|(14[57]\d{8})|(15[0-35-9]\d{8})|(17[36-8]\d{8})|(18[0-9]\d{8})|(170[057-9]\d{7})

    但此时,我们还是可以看出一些规律可以来简化这个正则表达式,类似初中数学的合并同类项,把\d{8}提取出来,简化为:
    ((13[0-9])|(14[57])|(15[0-35-9])|(17[36-8])|(18[0-9]))\d{8}|(170[057-9]\d{7})
    为了更明显的查看分组,我们可以用分组括号把((13[0-9])|(14[57])|(15[0-35-9])|(17[36-8])|(18[0-9]))\d{8}包含起来,变为:
    (((13[0-9])|(14[57])|(15[0-35-9])|(17[36-8])|(18[0-9]))\d{8})
    于是,完整的正则就变为了:
    (((13[0-9])|(14[57])|(15[0-35-9])|(17[36-8])|(18[0-9]))\d{8})|(170[057-9]\d{7})

    4、优化
    上面这个正则表达式已经可以投入编程使用了,但这个这个正则表达式分组有点多,获取捕获组的个数:
    <pre>
    String regex="(((13[0-9])|(14[57])|(15[0-35-9])|(17[36-8])|(18[0-9]))\d{8})|(170[057-9]\d{7})";
    Matcher m=Pattern.compile(regex).matcher("");
    System.out.println(m.groupCount());
    </pre>
    可以得到8个分组,但如果我们只是用来校验的话,直接用非捕获组就可以了,这样可以提高一些性能。
    提示:()捕获组会把匹配到的数据缓存起来,(?:)非捕获组不会缓存匹配到的数据。
    借助正则工具,我们可以很清晰得看到分组的情况:

    regex.png

    改为非捕获组后,正则变为:(?:(?:(?:13[0-9])|(?:14[57])|(?:15[0-35-9])|(?:17[36-8])|(?:18[0-9]))\d{8})|(?:170[057-9]\d{7})
    此时在RegexBuddy正则工具上可以看到0个分组

    regex2.png

    5、结果
    最终我们得到的正则表达式为
    (?:(?:(?:13[0-9])|(?:14[57])|(?:15[0-35-9])|(?:17[36-8])|(?:18[0-9]))\d{8})|(?:170[057-9]\d{7})

    6、正则工具
    RegexBuddy正则工具:http://download.csdn.net/detail/linbilin_/9699833
    在线工具:
    http://regexr.com/
    https://regex101.com/

    相关文章

      网友评论

      • b694c18695b6:一般都不做限制了
        梦蓝蓝的:@Evans_Music 嗯,如果不想限制的话,可以直接用^1\d{10}$。不过我这边只是写下编写正则的一个基本思路 :smile:

      本文标题:验证手机号码格式的正则表达式编写思路详解

      本文链接:https://www.haomeiwen.com/subject/coysmttx.html