【问题标题】:Perl phone-number regexPerl 电话号码正则表达式
【发布时间】:2016-04-29 04:21:31
【问题描述】:

对不起,问了这么简单的问题,我还是一个没有经验的程序员。我在工作的一些旧 perl 代码中偶然发现了一个电话号码匹配的正则表达式,如果有人能准确解释它的含义,我会很高兴(我的正则表达式技能严重缺乏)。

if ($value !~ /^\+[[:space:]]*[0-9][0-9.[:space:]-]*(\([0-9.[:space:]-]*[0-9][0-9.[:space:]-]*\))?([0-9.[:space:]-]*[0-9][0-9.[:space:]-]*)?([[:space:]]+ext.[0-9.[:space:]-]*[0-9][0-9.[:space:]-]*)?$/i) {
    ...
}

提前谢谢你:)

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    代码大致说“你应该用Number::Phone替换它”。

    抛开所有的玩笑和好建议不谈,找出正则表达式时要做的第一件事就是用/x 扩展它。第一步是按捕获组分解。

    /^
     \+[[:space:]]*[0-9][0-9.[:space:]-]*
     (\([0-9.[:space:]-]*[0-9][0-9.[:space:]-]*\))?
     ([0-9.[:space:]-]*[0-9][0-9.[:space:]-]*)?
     ([[:space:]]+ext.[0-9.[:space:]-]*[0-9][0-9.[:space:]-]*)?
    $/xi
    

    然后,由于这是由字符集主导的,我将按字符集进行空格。

    /^
     \+ [[:space:]]* [0-9] [0-9.[:space:]-]*
     ( \( [0-9.[:space:]-]* [0-9] [0-9.[:space:]-]* \) )?
     ( [0-9.[:space:]-]* [0-9] [0-9.[:space:]-]* )?
     ( [[:space:]]+ ext . [0-9.[:space:]-]* [0-9] [0-9.[:space:]-]* )?
    $/xi
    

    现在您可以开始看到一些类似的元素。尝试排列它们以查看相似之处。

    /^
     \+        [[:space:]]* [0-9] [0-9.[:space:]-]*
     ( \( [0-9.[:space:]-]* [0-9] [0-9.[:space:]-]* \) )?
     (    [0-9.[:space:]-]* [0-9] [0-9.[:space:]-]*    )?
     ( [[:space:]]+ 
       ext . 
          [0-9.[:space:]-]* [0-9] [0-9.[:space:]-]* 
     )?
    $/xi
    

    然后在一个元素上归零并尝试找出它。这是重要的,[0-9.[:space:]-]* 意思是“零个或多个数字、空格、破折号或圆点”。这对于电话解析没有多大意义,也许在上下文中会更有意义。让我们看一行我们可以猜出它试图做什么。

    ( \( [0-9.[:space:]-]* [0-9] [0-9.[:space:]-]* \) )?
    
    • 打开括号。
    • 零个或多个数字、空格、破折号或圆点。
    • 一个数字
    • 零个或多个数字、空格、破折号或圆点。
    • 关闭括号。

    括号表明这是试图解析区号。其余的将其限制为任意数量的数字、空格、破折号或圆点,但[0-9] 确保至少有一个数字。这可能是作者处理多种电话号码格式的方式。

    让我们给它起个名字,叫它phone_chars,因为这是作者决定电话号码的来源。还有另一个元素,[0-9.[:space:]-]* [0-9] [0-9.[:space:]-]*,我将其称为“电话原子”,因为作者决定电话号码的原子可以是它。如果我们把它放在它自己的正则表达式中并用它构建电话正则表达式,事情就会变得清晰得多。

    my $phone_chars = qr{[0-9.[:space:]-]};
    my $phone_atom  = qr{$phone_chars* [0-9] $phone_chars*}x;
    
    /^
     \+ [[:space:]]* [0-9] $phone_chars*
     ( \( $phone_atom \) )?
     (    $phone_atom    )?
     ( [[:space:]]+ ext . $phone_atom )?
    $/xi;
    

    如果您对电话号码有所了解,是这样的:

    1. 强制性国家代码(必须以 + 和数字开头)
    2. 可选区号
    3. 可选电话号码
    4. 可选扩展

    这个正则表达式不能很好地验证电话号码。根据这个正则表达式,“+1”是一个有效的电话号码,但“(555) 123-4567”不是因为它没有国家代码。

    电话号码验证很难。我提到Number::Phone了吗?

    use strict;
    use warnings;
    use v5.10;
    
    use Number::Phone;
    
    my $number = Number::Phone->new("+1(555)456-2398");
    say $number->is_valid;
    

    【讨论】:

    • 你太棒了。非常感谢:)
    • 伙计,你速度很快! :-)
    【解决方案2】:

    扩展模式、一点空白和几个 cmets 可以做到的事情令人惊叹……

    if ($value !~  /
          ^                 # Anchor to start of string
    
         \+                 # followed (immediately) by literal '+'
         [[:space:]]*       # zero or more chars in the POSIX character class 'space'
         [0-9]              # compolsory digit
         [0-9.[:space:]-]*  # zero or more digit, full-stop, space or hyphen
    
         (                  # start capture to $1
             \(                   # Literal open parentheses
             [0-9.[:space:]-]*    # zero or more ... (as above)
             [0-9]                # compolsory digit
             [0-9.[:space:]-]*    # zero or more ... (as above)
             \)                   # Literal close parentheses
         )?                 # close capture to $1 - whole thing optional
    
         (                  # start capture to $2
             [0-9.[:space:]-]*    # zero or more ... (as above)
             [0-9]                # compolsory digit
             [0-9.[:space:]-]*    # zero or more ... (as above)
         )?                 # close capture to $2 - whole thing optional
    
         (                  # start capture to $3
             [[:space:]]+         # at least one space (as definned by POSIX)
             ext.                 # literal 'ext' followed by any character
             [0-9.[:space:]-]*    # zero or more ... (as above)
             [0-9]                # compolsory digit
             [0-9.[:space:]-]*    # zero or more ... (as above)
         )?                 # close capture to $3 - whole thing optional
    
          $                 # Anchor to end of string
                  /ix       # close regex; ignore case, extended mode options
       )  {
    

    【讨论】:

    • 谢谢马蒂 :)
    猜你喜欢
    • 1970-01-01
    • 2017-09-23
    • 2014-02-15
    • 1970-01-01
    • 2016-02-02
    • 2011-12-14
    • 2013-05-26
    • 1970-01-01
    相关资源
    最近更新 更多