正则表达式,用于匹配特定的电话号码

时间:2019-05-20 04:24:59

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

我正在尝试查看字符串是否与我所在国家/地区的电话号码格式匹配,这是区号(两位数字,可以或可以不以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}错误。

我在这里做什么错了?

5 个答案:

答案 0 :(得分:3)

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

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

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

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

答案 1 :(得分:3)

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

  • 在开头放置一个optional capturing group并在其中加上一个开头括号:
    ^(\()?
  • 稍后在模式中的任何地方检查是否成功:
    (?(1)\) |[ -])
    如果成功,则要求结束),后接空格 |其他:[ -]空格或破折号。

因此,带有条件的整个模式可能是

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

请参见demo at RubularRegex101。进一步调整以适应您的需求。

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

答案 2 :(得分:2)

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

[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}`);
    });
}

RegEx

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

enter image description here

RegEx电路

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

enter image description here


编辑1:

对于(),我们要在初始表达式中添加两个否定的后向。也许similar to this

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

enter image description here

答案 3 :(得分:2)

我相信您可以使用以下正则表达式。

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)

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

  • 数字正在传递到仅接受特定格式的系统,因此您知道这些确切的格式,其他任何格式都无法使用
  • 数字只是人类读取的,因此您可以让他们弄清楚,而不必进行任何验证

否则,您应该使用https://github.com/mobi/telephone_number之类的健壮库(受Google libphonenumber启发)