当前位置:

学习正则表达式 - 电话号码

访客 2024-01-05 1090 0

正则表达式是描述一组字符串特征的模式,用来匹配特定的字符串。

一、需求

写一个正则表达式匹配电话号码,并且括号、连字符或点号都是可选的。假定合规数据只包含以下15种匹配模式之一:

  1. xxxxxxx8277019
  2. xxx.xxxx827.7019
  3. xxx-xxxx827-7019
  4. xxxxxxxxxx7078277019
  5. xxxxxx.xxxx707827.7019
  6. xxxxxx-xxxx707827-7019
  7. xxx.xxxxxxx707.8277019
  8. xxx.xxx.xxxx707.827.7019
  9. xxx.xxx-xxxx707.827-7019
  10. xxx-xxxxxxx707-8277019
  11. xxx-xxx.xxxx707-827.7019
  12. xxx-xxx-xxxx707-827-7019
  13. (xxx)xxxxxxx(707)8277019
  14. (xxx)xxx.xxxx(707)827.7019
  15. (xxx)xxx-xxxx(707)827-7019

二、实现

1.创建表并生成测试数据

  • createtablet_regexp(atext);
  • insertintot_regexpvalues
  • --合规数据
  • ('8277019'),
  • ('827.7019'),
  • ('827-7019'),
  • ('7078277019'),
  • ('707827.7019'),
  • ('707827-7019'),
  • ('707.8277019'),
  • ('707.827.7019'),
  • ('707.827-7019'),
  • ('707-8277019'),
  • ('707-827.7019'),
  • ('707-827-7019'),
  • ('(707)8277019'),
  • ('(707)827.7019'),
  • ('(707)827-7019'),
  • --噪声数据
  • ('a277019'),
  • ('abc827-7019'),
  • ('8a2b7c-7019'),
  • ('.827-7019'),
  • ('70711-827-7019'),
  • ('(707)-827-7019'),
  • ('(707).827-7019'),
  • ('707-827-701912'),
  • ('(707.827-7019'),
  • ('(707827-7019');
  • 2.编写正则表达式

    ^(\(\d{3}\)|\d{3}[.-]?)?\d{3}[.-]?\d{4}$

    3.使用regexp函数查询验证

  • --注意SQL中要使用\对正则表达式中的转义字符\进行转义,看起来就如下为两个连续的\:\\
  • select*fromt_regexp
  • wherearegexp'^(\\(\\d{3}\\)|\\d{3}[.-]?)?\\d{3}[.-]?\\d{4}$';
  • 三、分析与知识点

    1.匹配字符串字面值

    707-827-7019

    上面这个正则表达式用字符串字面值(stringliteral)来匹配目标字符串。所谓字符串字面值,就是字面上看起来是什么就是什么。

    2.使用字符组匹配数字

    [0-9]

    正则表达式[0-9]的含义是“匹配0到9范围内的任意数字”。正则表达式将方括号视为特殊的元字符(metacharacter),因此方括号不参与匹配。元字符是在正则表达式中有特殊含义的字符,也是保留字符。[0-9]这种形式的正则表达式称做字符组(characterclass)。可以对数字的范围进行进一步限定,比如:

    [012789]

    这个字符组只会匹配列出的数字,即0、1、2、7、8、9。要匹配任意10位以连字符分隔的电话号码,可以使用以下正则表达式:

    [0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]

    这是可以的,但太长了,更好的方法是采用简写形式。

    3.使用字符组简写式匹配一位数字

    \d可以像[0-9]一样匹配任意阿拉伯数字。这种正则表达式叫做字符组简写式(charactershorthand)。可以使用以下表达式来匹配电话号码中的任意数字:

    \d\d\d-\d\d\d-\d\d\d\d

    重复\d三次和四次就可以分别匹配三个和四个数字。该表达式中的连字符是一个字面值,因此会被原样匹配。除了和上面表达式一样,使用连字符本身(-)来匹配连字符之外,也可以用转义的大写D(\D),它匹配任何一个非数字字符。以下示例使用了\D来匹配连字符:

    \d\d\d\D\d\d\d\D\d\d\d\d

    4.匹配任意字符

    还可以用点号(.)来匹配连字符:

    \d\d\d.\d\d\d.\d\d\d\d

    点号(英文句号)是一个通配符,可以匹配任意字符(但某些情况下不能匹配行起始符)。以上示例中的正则表达式匹配了连字符,但它也可以匹配百分号(%):

    707�7p19

    或者是竖线(|):

    707|827|7019

    亦或其他字符。

    5.使用捕获分组和后向引用

    可以使用捕获分组(capturinggroup)来匹配电话号码中的某一部分,然后使用后向引用(backreference)对分组中的内容进行引用。要创建捕获分组,先将一个\d放在一对圆括号中,这样就将它放入了一个分组中,后面可以用\1来对捕获的内容进行后向引用:

    (\d)\d\1

    \1对括号内分组捕获的内容进行了反向引用。(\d)匹配第一个数字并将其捕获;\d匹配第二个数字但没有捕获,因为没有括号;\1对捕获的数字进行反向引用。这个正则表达式只匹配了区号。现在可以用一个分组和几个后向引用对整个电话号码进行匹配:

    (\d)0\1\D\d\d\1\D\1\d\d\d

    6.使用量词

    现在用另一种语法来匹配电话号码:

    \d{3}-?\d{3}-?\d{4}

    花括号中的数字表示待查找的数字出现的次数。包含数字的花括号是一种量词(quantifier)。花括号本身用做元字符。问号是另一种量词,在以上表达式中表示连字符是可选的。也就是说,连字符可以不出现或只出现一次。还有其他的量词,例如加号()表示“一个或多个”,星号(*)表示“零个或多个”。使用量词能让正则表达式变得更简洁:

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

    加号表示出现一次或多次。这个正则表达式表示括号里的模式出现一次或多次,括号里的模式匹配三位或四位数字,后跟一个连字符或一个点号。下面逐一解释表达式中的每一项:左圆括号(为捕获分组的起始符;反斜杠\为字符组简写式的起始符(对之后的字符进行转义);字符d为字符组简写式的结束符(d匹配0到9范围内的任意数字);左花括号{为量词起始符;数字3为匹配的最小数量;逗号,隔开不同的数量;数字4为匹配的最大数量;右花括号}为量词的结束符;左方括号[为字符组的起始符;点号.(匹配点号本身);连字符-匹配连字符的本身;右方括号]为字符组的结束符;问号?表示量词“零个或一个”;右圆括号)为捕获分组的结束符;加号表示量词“一个或多个”。这个表达式只能匹配3位或4位的数字,而不管是否符合电话号码的格式。我们来改进一下:

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

    这个表达式匹配的字符串是连续两个无括号的三位数字,每三位数字后可以带连字符也可以不带,最后是一个四位数字。这个正则表达式有问题,从https://www.dute.org/regex在线测试结果一目了然。

    对于测试数据,合规数据仅匹配了具有区号且区号不带括号的数据:

    而噪声数据也匹配了4个:

    问题出在对字符串首尾和区号的匹配上,下面加以改进。

    7.括选文字符

    这个正则表达式表示第一个3位数字可以带也可以不带括号,即区号是可选的:

    ^(\(\d{3}\)|\d{3}[.-]?)?\d{3}[.-]?\d{4}$

    为了便于理解,我们再按匹配次序看一下表达式中的各项。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

    运算符说明\转义符(),(?:),(?=),[]小括号和中括号*,,?,{n},{n,},{n,m}限定符^,$,\任何元字符、任何字符定位点和序列(即:位置和顺序)|“或”操作。字符具有高于或运算符的优先级,使得“m|food”匹配“m”或“food”。若要匹配“mood”或“food”,需使用括号创建子表达式,从而产生“(m|f)ood”。\(\d{3}\)|\d{3}[.-]?

    \(表示左括号本身;\d匹配一位数字;\d之后的{3}是量词,表示匹配三位数字;\)匹配右括号本身;竖线符|表示选择,也就是从多个可选项中选择一个;\d匹配一位数字;{3}是表示匹配三位数字的量词;[.-]?匹配一个可选的点号或连字符。这部分表达式表示“匹配一个带括号的区号,或一个不带括号但可能包含连字符的区号”:

    (xxx)
    xxx
    xxx.
    xxx-

    ^(\(\d{3}\)|\d{3}[.-]?)?

    出现在正则表达式起始位置的脱字符^,表示0个或1个区号会出现在一行的起始位置,如下的噪声数据将被过滤掉:
    70711-827-7019
    (707.827-7019
    (707827-7019

    \d{3}[.-]?

    \d匹配一位数字;{3}表示匹配三位数字的量词;[.-]?匹配另一个可选的点号或连字符;

    \d{4}$

    \d匹配一位数字;{4}是表示匹配四位数字的量词;美元符$匹配行结束位置,即以4位数字结尾,如下的噪声数据将被过滤掉:
    707-827-701912

    注意^的位置,一定要在分组外。如果要放到分组内:

    (^\(\d{3}\)|^\d{3}[.-]?)?\d{3}[.-]?\d{4}$

    则只要符合\d{3}[.-]?\d{4}$的数据都会被匹配到:

    发表评论

    • 评论列表
    还没有人评论,快来抢沙发吧~