正则表达式仅在特定字符之前出现时匹配字符(条件正则表达式)

4 投票
2 回答
4948 浏览
提问于 2025-04-17 18:29

我正在开发一个用于以色列手机号码的正则表达式。目前我有:

re.compile(r'^[\(]?0?(5[023456789])\)?(\-)?\d{7}$')

这个表达式可以匹配大部分情况。问题是,我想让第二个括号只在第一个括号出现时才匹配。

比如说,(055)-5555555、(055)5555555 或 0555555555 都能匹配,但像 055)-5555555 这样的就不行。

我知道可以用两个正则表达式来测试这个条件(如果第一个匹配,就测试第二个),但这样似乎不是个聪明的解决办法。

我想我需要类似正则表达式的前瞻匹配,但不太确定怎么用,或者我是否理解这个概念。

编辑:解释一下逻辑

区号:应该以5开头,然后是一个特定列表中的单个数字,前面可以有一个可选的零。这个区号也可能在括号里。

接着是一个可选的连字符,后面跟着7个数字。

澄清:我需要让两个括号都匹配,前提是另一个括号存在,这一点对于第一个括号也是如此,我之前没有提到这一点。

2 个回答

3

使用 (?(id/name)yes-pattern|no-pattern) 这种写法,可以让你只在开括号匹配的情况下,匹配到闭括号。

re.compile(r'^(\()?0?(5[023456789])(?(1)\))-?\d{7}$')

这里的 (?(1)\)) 这部分的意思是,如果有第1组(也就是开括号),那么就匹配 \) 这个闭括号(后面的 | 后面没有模式是可选的)。

演示:

>>> phone.search('(055)-5555555')
<_sre.SRE_Match object at 0x101e18a48>
>>> phone.search('055)-5555555') is None
True
9

首先,你需要捕捉到开括号,然后使用一个条件模式我知道这个链接是指向php.net的,但我觉得它在引用正则表达式时很有用,它还包含了一个正好符合你情况的例子),这个条件模式只有在第一个开括号匹配时才会被应用。

这个模式是..

^(\()?0?(5[02-9])(?(1)\))-?(\d{7})$

它会匹配

(055)-5555555
(055)5555555 
0555555555

不匹配

055)-5555555

捕获的组

  1. 开括号(如果没有找到则为空)
  2. 区号(例如:55)
  3. 电话号码(例如:5555555)

它是如何工作的

部分(\()?用于匹配开括号。这个是可选的。

部分(?(1)\))检查第一个捕获的组(在我们的例子中是开括号)是否有匹配,如果,那么这个字符串必须也要匹配闭括号。

如果没有找到开括号,这个条件就会被忽略。

撰写回答