正则表达式红宝石电话号码

时间:2015-05-09 12:16:04

标签: ruby regex rubular

我正在试图弄清楚如何编写自己的正则表达式。

我列出了可行的电话号码和不可行的电话号码,并试图确保包含可行的电话号码,但我无法弄清楚如何完成它。

允许列表

0665363636 //
06 65 36 36 36 //
06-65-36-36-36 //
+33 6 65 36 36 36

不允许

06 65 36 36 //
2336653636 //
+3366536361 //
0065363636 

我搞砸了一下,我现在有这个:

[0+][63][6 \-3][56\ ][\d{1}][\d \-]\d{2}[\d{1} \-]\d\d? ?\-?\d?\d? ?\d?\d?$

这阻止了非允许的2号和4号,但我似乎无法弄清楚如何阻止其他的。

我应该提供最少数量的数字吗?如果是这样我将如何做到这一点。

2 个答案:

答案 0 :(得分:2)

[编辑:发布此内容后,我发现它与@Lucas的答案非常相似。但是,我会让它代表替代演示文稿。]

我会尝试为每个允许的模式构建一个正则表达式,然后使用它们的联合来获得单个正则表达式。

我们发现所有不以+开头的允许数字都有10个数字,所以我认为这是一个要求。如果允许使用不同数量的数字,则可以轻松处理。

<强> 1。包括0665363636,不包括2336653636和0065363636

我认为这意味着号码必须以数字0开头,第二个数字不能是0。这很简单:

r1 = /
     ^     # match start of string
     0     # match 0
     [1-9] # match any digit 1-9
     \d{8} # match 8 digits
     $     # match end of string
     /x

测试:

'0665363636' =~ r1 #=> 0
'2336653636' =~ r1 #=> nil
'0065363636' =~ r1 #=> nil 

这似乎有效。

<强> 2。包括06 65 36 36 36,不包括06 65 36 36

另一个简单的方法:

r2 = /
     ^       # match start of string
     0       # match 0
     [1-9]   # match any digit 1-9 # or \d if can be zero
     (?:     # begin a non-capture group
       \s    # match one whitespace
       \d{2} # match two digits
     )       # end capture group
     {4}     # match capture group 4 times
     $       # match end of string
     /x

测试:

'06 65 36 36 36' =~ r2 #=> 0
'06 65 36 36'    =~ r2 #=> nil

另一个明显的成功!

我们也看到06-65-36-36-36也应该被允许。这是上面的一个小变体,我们不必费心创建另一个正则表达式以包含在联合中;相反,我们只是稍微修改r2

r2 = /^0[1-9](?:
      [\s-] # match one whitespace or a hyphen
      \d{2}){4}$
     /x

请注意,当它在字符类中时,我们不必转义连字符。

测试:

'06 65 36 36 36' =~ r2 #=> 0
'06-65-36-36-36' =~ r2 #=> 0

是!

第3。包括+33 6 65 36 36 36,不包括+3366536361

看起来,当数字以+开头时,+后面必须跟两个数字,一个空格,一个数字,一个空格,然后用空格分隔四对数字。我们可以写下来:

r3 = /
     ^       # match start of string
     \+      # match +
     \d\d    # match two digits
     \s\d    # match one whitespace followed by a digit
     (?:     # begin a non-capture group
       \s    # match one whitespace
       \d{2} # match two digits
     )       # end capture group
     {4}     # match capture group 4 times
     $       # match end of string
     /x

测试:

'+33 6 65 36 36 36' =~ r3 #=> 0
'+3366536361'       =~ r3 #=> nil

Nailed it!

<强>组织工会!

r = Regexp.union(r1, r2, r3)
 => /(?x-mi:
         ^     # match start of string
         0     # match 0
         [1-9] # match any digit 1-9
         \d{8} # match 8 digits
         $     # match end of string
         )|(?x-mi:^0[1-9](?:
          [\s-] # match one whitespace or a hyphen
          \d{2}){4}$
         )|(?x-mi:
         ^       # match start of string
         \+      # match +
         \d\d    # match two digits
         \s\d    # match one whitespace followed by a digit
         (?:     # begin a non-capture group
           \s    # match one whitespace
           \d{2} # match two digits
         )       # end capture group
         {4}     # match capture group 4 times
         $       # match end of string
         )/ 

我们试一试:

['0665363636', '06 65 36 36 36', '06-65-36-36-36',
 '+33 6 65 36 36 36'].any? { |s| (s =~ r).nil? } #=> false

['06 65 36 36', '2336653636', '+3366536361',
 '0065363636'].all? { |s| (s =~ r).nil? } #=> true

宾果!

<强>效率

联合个人正则表达式可能无法产生最有效的单一正则表达式。您必须确定更容易的初始初始构建和测试以及持续维护的好处是否值得效率损失。如果效率至关重要,您仍然可以用这种方式构造r,然后手动调整它。

答案 1 :(得分:1)

您希望仅将允许的电话号码限制为法国移动电话号码。

你列出了有效和无效的字符串,这是一个很好的起点。但是,我认为你只想一次性编写模式,这很容易出错。

让我们按照一个简单的方法,浏览一下允许列表,为每一个创建一个非常简单的正则表达式:

0665363636         -> ^06\d{8}$
06 65 36 36 36     -> ^06(?: \d\d){4}$
06-65-36-36-36     -> ^06(?:-\d\d){4}$
+33 6 65 36 36 36  -> ^\+33 6(?: \d\d){4}$

到目前为止一切顺利。

现在,只需将所有内容组合成一个正则表达式,然后稍微考虑一下(06部分在前3个案例中很常见):

^06(?:\d{8}|(?: \d\d){4}|(?:-\d\d){4})|\+33 6(?: \d\d){4}$

Etvoilà。 Demo here

作为旁注,您应该使用:

^0[67](?:\d{8}|(?: \d\d){4}|(?:-\d\d){4})|\+33 [67](?: \d\d){4}$

法国手机号码也可以在07年开始。