Python re.findall()不适用于可选匹配(使用问号)

时间:2018-11-29 16:43:53

标签: python regex

据我正在阅读的在线教程指出:

与问号的可选匹配

“有时,您只需要可选地匹配一个模式。即,正则表达式应该找到匹配项,无论是否存在该文本位。?字符将其前面的组标记为的可选部分例如,在交互式外壳程序中输入以下内容:“

>>> batRegex = re.compile(r'Bat(wo)?man')
>>> mo1 = batRegex.search('The Adventures of Batman')
>>> mo1.group()
'Batman'

我的问题:

我正在尝试以123-456-7890(无国家代码)或(111)-123-456-7890(有国家代码)的形式查找匹配的电话号码。

这是我的python正则表达式代码,用于返回匹配的电话号码列表:

phone_num_regex = re.compile(r'(\(\d{3}\)-)?\d{3}-\d{3}-\d{4}')
phone_num_list = phone_num_regex.findall('800-420-7240 (933)-415-863-9900 415-863-9950')

但是,我获得的phone_num_list是['', '(933)-', ''],而不是我想要的['800-420-7240, '(933)-415-863-9900', '415-863-9950']

我可以知道我的代码有什么问题吗?我猜这与“?”有关(可选匹配项)

1 个答案:

答案 0 :(得分:1)

您要将可选部分包含在捕获组中,这意味着re.findall所给的就是这些组。

如果您改用非捕获组,则不会发生这种情况。

re.compile(r'(?:\(\d{3}\)-)?\d{3}-\d{3}-\d{4}')

来自the docs

  

(...)
      匹配括号内的任何正则表达式,并指示组的开始和结束;可以在执行匹配后检索组的内容,并且以后可以在字符串中使用\number特殊序列进行匹配,如下所述。要匹配文字'('')',请使用\(\),或将它们括在字符类中:[(][)]。 / p>

  

(?:...)
      非捕获版本的常规括号。匹配括号内的任何正则表达式,但执行匹配后无法检索该组匹配的子字符串,也无法在模式的稍后引用。

  

re.findall(pattern, string, flags=0)
      返回字符串中模式的所有非重叠匹配项,作为字符串列表。从左到右扫描该字符串,并以找到的顺序返回匹配项。 如果该模式中存在一个或多个组,请返回组列表;如果模式包含多个组,则这将是一个元组列表。空匹配项包含在结果中。

(重点是我的)