【问题标题】:RegEx for matching specific phone numbers用于匹配特定电话号码的正则表达式
【发布时间】:2019-05-20 04:24:59
【问题描述】:

我正在尝试查看字符串是否与我所在国家/地区的电话号码格式匹配,即区号(前面可能有也可能没有 0,也可能在括号之间的两位数字)后跟 8 位或 9 位数字其中最后 4 位数字之前可能有一个破折号。 以下是一些有效的格式:


'00 00000000'
'000-000000000'
'000 00000-0000'
'00 0000-0000'
'(00) 0000-0000'
'(000) 000000000'

到目前为止,这是我的工作表达式:


p = /0?\d{2}\s?-?\s?\d{4,5}\s?-?\s?\d{4}/

我尝试使用条件来查看区号是否在 /?(\() 0?\d{2}\)|0?\d{2} \s?-?\s?\d{4,5}\s?-?\s?\d{4}/ 的括号内,但出现 (repl):1: target of repeat operator is not specified: /?(\() 0?\d{2}\)|0?\d{2} \s?-?\s?\d{4,5}\s?-?\s?\d{4} 错误。

我在这里做错了什么?

【问题讨论】:

  • 你能举一些电话号码包含括号的例子吗?
  • 当你说 9 位数字时,你的意思是 4 位数字,破折号,然后是 4 位数字吗?
  • 刚刚添加了示例。
  • 可以是4位短划线后4位,也可以是5位短划线后4位。
  • 我已经发布了一个解决括号问题的答案,请随时查看

标签: regex ruby regex-lookarounds regex-group regex-greedy


【解决方案1】:

不要使用正则表达式验证电话号码。我敢打赌,您不希望排除那些偶尔输入 2 个后续空格或其他内容的人。

相反,过滤掉所有非数字和前导零,然后进行验证。像这样:

number.gsub(/\D+/, '').gsub(/\A0+/) =~ /\d{8,9}/

我不确定它是否能开箱即用地满足您的需求,但我敢打赌您已经明白了。毕竟,[000]1234 56789 是一个可以理解的电话号码。

【讨论】:

  • 谢谢!这是个好主意,我一定会这样做的。
  • mudsie,我相信你的意思是.gsub(/\A0+/, '')。这并没有告诉我们一个字符串是否代表一个有效的电话号码,但这不是想法吗?例如,"Something like 99.473218% of Rubiests use snake case for names of variables and methods.".gsub(/\D+/, '').gsub(/\A0+/, '') =~ /\d{8,9}/ #=> 0。我通过拨打该号码确认了这一点,但没有听到铃声。
  • 这不也是不符合要求的,因为只应该忽略单个前导0吗?
  • 如果要求是吓唬用户,或者玩正则表达式高尔夫,那么是的,以上不起作用。如果目标是验证用户的输入,那么这是唯一的方法。因为当他们拒绝我输入的号码时,因为他们有一个复杂的正则表达式,你知道,我关闭了页面。永远。毕竟,555 个数字会通过,而它们肯定是无效的。
  • 但是如果它接受无效的输入,然后他们就不能给你打电话,因为他们存储了一个无效的号码......这也很烦人
【解决方案2】:

我的回答解决了您对可选括号的conditional 想法。
Ruby 从 v2.0 开始支持条件。 syntax 是 (?(A)X|Y):如果 A 为真,则 X 否则 Y。

  • 在开头放置一个包含左括号的optional capturing group:
    ^(\()?
  • 稍后在模式中的任何位置检查是否成功:
    (?(1)\) |[ -])
    如果成功:需要关闭 ) 后跟空格 | 其他:[ -] 空格或破折号。

所以有条件的整个模式可以是

^(\()?0?\d{2}(?(1)\) |[ -])\d{4,5}[ -]?\d{4}$

请参阅demo at Rubular 或Regex101。进一步调整您的需求。

我认为@CarySwoveland 已经回答了@AlekseiMatiushkin 的回答肯定会让生活更轻松。

【讨论】:

  • 条件表达式对我来说是新的,当然是我工具带中值得补充的。考虑到它非常有用,而且 Ruby v2.0 已经发布了这么久,我很惊讶我之前在 SO 没有看到它使用过。
【解决方案3】:

相信你可以使用下面的正则表达式。

R = /
    \A            # match beginning of string
    (?:           # begin a non-capture group
      \(0?\d{2}\) # match '(' then an optional `0` then two digits then ')'
    |             # or
      0?\d{2}     # match an optional `0` then two digits
    )             # end the non-capture group
    (?:           # begin a non-capture group
      [ ]+        # match one or more spaces
    |             # or
      -           # match a hyphen
    )             # end the non-capture group
    \d{4,5}       # match 4 or 5 digits
    -?            # optionally match a hyphen
    \d{4}         # match 4 digits
    \z            # match end of string
    /x            # free-spacing regex definition mode

arr = [
  '00 00000000',
  '000-000000000',
  '000 00000-0000',
  '00 0000-0000',
  '(00) 0000-0000',
  '(000) 000000000',
  '(000 000000000',
  '(0000) 000000000'
]

arr.map { |s| s.match? R }
  #=> [true, true, true, true, true, true, false, false]

正则表达式通常写成如下。

R = /\A(?:\(0?\d{2}\)|0?\d{2})(?: +|-)\d{4,5}-?\d{4}\z/

如果前导数字不能为零,则应按如下方式更改。 (例如,如果'001-123456789' 和'(12)-023456789' 无效。)

R = /\A(?:\(0?[1-9]\d\)|0?\[1-9]\d)(?: +|-)[1-9]\d{3,4}-?\d{4}\z/

【讨论】:

    【解决方案4】:

    可能有几种方法可以验证这些数字。一种方法是,我们写下所有可能的电话号码,然后为它写一个表达式。也许,类似于:

    [0-9]{2,3}(\s|-)[0-9]{4,5}-?[0-9]{3,4}
    

    测试

    re = /[0-9]{2,3}(\s|-)[0-9]{4,5}-?[0-9]{3,4}/m
    str = '\'00 00000000\'
    \'000-000000000\'
    \'000 00000-0000\'
    \'00 0000-0000\''
    
    # Print the match result
    str.scan(re) do |match|
        puts match.to_s
    end
    

    演示

    这个 sn-p 只是为了显示捕获组,并且表达式可能有效:

    const regex = /[0-9]{2,3}(\s|-)[0-9]{4,5}-?[0-9]{3,4}/gm;
    const str = `'00 00000000'
    '000-000000000'
    '000 00000-0000'
    '00 0000-0000'`;
    let m;
    
    while ((m = regex.exec(str)) !== null) {
        // This is necessary to avoid infinite loops with zero-width matches
        if (m.index === regex.lastIndex) {
            regex.lastIndex++;
        }
        
        // The result can be accessed through the `m`-variable.
        m.forEach((match, groupIndex) => {
            console.log(`Found match, group ${groupIndex}: ${match}`);
        });
    }

    正则表达式

    如果不需要此表达式,可以在 regex101.com 中修改或更改。

    正则表达式电路

    jex.im 也有助于将表达式可视化。


    编辑 1:

    在() 的情况下,我们想在我们的初始表达式中添加两个否定的lookbehind。也许,similar to this:

    \(?[0-9]{2,3}\)?(\s|-)[0-9]{4,5}-?[0-9]{3,4}
    

    【讨论】:

    • 前导 [0-9]{2,3} 将匹配 999,根据 OP 必须排除。
    • 是的,但是如果我输入0?\d{2},它应该会这样做,对吧?
    • 我刚刚使用括号添加了更多示例
    • 嗨@Emma,它是almos this,但它不能匹配像(00 0000-0000这样只有左括号或右括号的字符串。此外,区号必须是可选的“0”,后跟两位数字。
    • @Emma 是,但是这种格式应该是无效的。我想在表达式中验证的是,如果区号之前有一个左括号,那么也应该有一个右括号。像 (0000000000 应该是无效的,但 0000000000 和 (00)000000000 应该是。
    【解决方案5】:

    除非您知道自己在非常、非常有限的范围内工作,否则不要这样做,例如

    • 这些数字被传递到只接受特定格式的系统,因此您知道这些确切的格式和其他格式都不起作用
    • 这些数字只是人工读取的,因此您可以让他们弄清楚,而无需验证任何内容

    否则,您应该使用像 https://github.com/mobi/telephone_number 这样的强大库(灵感来自 Google 的 libphonenumber)

    【讨论】:

      猜你喜欢
      • 2010-12-16
      • 1970-01-01
      • 1970-01-01
      • 2020-01-18
      • 2022-01-03
      • 1970-01-01
      • 1970-01-01
      • 2011-09-22
      • 1970-01-01
      相关资源
      最近更新 更多