用于匹配特定 phone 数字的正则表达式

RegEx for matching specific phone numbers

我正在尝试查看一个字符串是否与我所在国家/地区的 phone 数字格式匹配,即区号(两个数字前面可能有也可能没有 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} 错误。

我做错了什么?

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

[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

演示

此代码段只是为了显示捕获组并且表达式可能有效:

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:

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

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

不要使用正则表达式验证 phone 数字。我打赌你不想排除那些偶尔输入 2 个后续空格或其他内容的人。

而是过滤掉所有 non-digits 和前导零,然后进行验证。像这样:

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

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

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

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/

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

  • 在开头放置一个包含左括号的 optional capturing group:
    ^(\()?
  • 稍后在模式中的任何地方检查它是否成功:
    (?(1)\) |[ -])
    如果成功:需要结束 ) 后跟 space | 否则:[ -] space 或破折号。

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

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

demo at Rubular or Regex101。根据您的需要进一步调整。

使用交替 (?:\(abc\)|abc) 的替代方法,@CarySwoveland 已经回答了,但我认为 @AlekseiMatiushkin 的回答肯定会让生活更轻松。

不要这样做,除非你知道你在非常、非常有限的范围内工作,例如

  • 这些数字被传递到一个只接受特定格式的系统,因此您知道这些格式完全正确,其他格式都行不通
  • 这些数字只是由人类读取的,因此您可以让他们自己弄明白,而不必验证任何东西

否则你应该使用像 https://github.com/mobi/telephone_number (inspired by Google's libphonenumber)

这样强大的库