2

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

我列出了可行的电话号码和不可行的电话号码,并试图确保包括可行的电话号码,但我不知道如何完成它。

允许列表

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 号,但我似乎无法弄清楚如何阻止其他的。

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

4

2 回答 2

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

看来,当数字以 a 开头时++必须后跟两位数字,一个空格,一位数字,一个空格,然后是四对以空格分隔的数字。我们可以把它写下来:

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

搞定了!

联合起来!

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这种方式构建,然后手动调整它。

于 2015-05-09T20:08:45.327 回答
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}$

等等瞧。演示在这里


作为旁注,您应该使用:

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

因为法国的手机号码也可以从 07 开始。

于 2015-05-09T12:45:08.760 回答