正则表达式未匹配可选字符串

2 投票
3 回答
545 浏览
提问于 2025-04-16 08:17

这个字符串 s 比较长,但我把它缩短了,方便理解。

>>> import re
>>> s = "Blah. Tel.: 555 44 33 22."
>>> m = re.search(r"\s*Tel\.:\s*(?P<telephone>.+?)\.", s)
>>> m.group("telephone")
'555 44 33 22'

上面的代码是可以工作的,但如果我把正则表达式用 ()? 包起来,让它变成可选的,我就找不到任何电话号码了。

>>> m = re.search(r"(\s*Tel\.:\s*(?P<telephone>.+?)\.)?", s)
>>> m
<_sre.SRE_Match object at 0x9369890>
>>> m.group("telephone")

这里面有什么问题呢?谢谢!

补充:

这是一个更大正则表达式的一部分,我正在从一个大文件的每一行中提取很多值。

regex = r"^(?P<title>.[^(]+);" \
         "\s*(?P<subtitle>.+)\." \
         "\s*Tel\.:\s*(?P<telephone>.+?)(\.|;)" \
         "\s*(?P<url>(www\.|http://).+?\.[a-zA-Z]+)(\.|;)" \
         "(\s*(?P<text>.+?)\.)?" \
         "\s*coor:(\s*(?P<lat>.+?),\s*(?P<long>.+?))?$"

一行示例可能是:

l = "Title title; Subtitle, subtitle. Tel.: 555 33 44 11. www.url.com. coor: 11.11111, -2.222222

还有另一行示例:

l = "Title2 title; Subtitle2, subtitle. Tel.: 555 33 44 11. www.url2.com. coor: 44.444444, -6.66666

这个正则表达式真的很复杂,所以我没有把它贴出来。

3 个回答

2

(anything)? 这个表达式会在你的字符串最开始的位置(在 Blah 之前)匹配到一个空字符串,所以它就满足了条件,不会继续往下查找了。

编辑:

如果你有很多行文本,而只有其中一些行包含你想要的字符串,可以试试下面的方法:

import re

rex = re.compile(r"\s*Tel\.:\s*(?P<telephone>.+?)\.")
for line in lines:
    m = rex.search(line)
    if m:
        print m.group("telephone")
2

这是因为空字符串是你的正则表达式可以匹配的有效结果,而且它比更长的匹配结果更受欢迎。

你可能想看看 re.findall

编辑: 你可以把可选的部分完全移出你的正则表达式:

import re
s = "Blah. Tel.: 555 44 33 22."
m = re.search(r"\s*Tel\.:\s*(?P<telephone>.+?)\.", s)
if m is not None:
  print m.group("telephone")
0

你的正则表达式对 titlesubtitle 的匹配规则太宽泛了。它们把电话号码的部分也包含进去了,如果把电话号码设为可选的,正则表达式就会继续匹配后面的部分(并且成功匹配)。只有在电话号码不是可选的情况下,正则引擎才会回溯,才能找到一个整体的匹配。

可以试试

regex = r"^(?P<title>[^;]+);" \
         "\s*(?P<subtitle>[^.]+)\." \
         "(\s*Tel\.:\s*(?P<telephone>.+?)(\.|;))?" \
         "\s*(?P<url>(www\.|http://).+?\.[a-zA-Z]+)(\.|;)" \
         "(\s*(?P<text>.+?)\.)?" \
         "\s*coor:(\s*(?P<lat>.+?),\s*(?P<long>.+?))?$"

撰写回答