混淆了Python中regex的用法

2024-09-28 03:21:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我对以下三种模式感到困惑,有人能详细解释一下吗?在

## IPython with Python 2.7.3
In [62]: re.findall(r'[a-z]*',"f233op")
Out[62]: ['f', '', '', '', 'op', '']  ## why does the last '' come out?

In [63]: re.findall(r'([a-z])*',"f233op")
Out[63]: ['f', '', '', '', 'p', '']  ## why does the character 'o' get lost?

In [64]: re.findall(r'([a-z]*)',"f233op")
Out[64]: ['f', '', '', '', 'op', '']  ## what's the different than line 63 above?

Tags: theinrewithipython模式outlast
3条回答

例1

re.findall(r'[a-z]*',"f233op")

此模式匹配零个或多个小写字母字符实例。零或更多的部分在这里是关键的,因为从字符串中的每个索引位置开始的无任何匹配与f或{}的匹配一样有效。返回的最后一个空字符串是从字符串结尾开始的匹配项(p和{}(字符串结尾)之间的位置)。在

例2

^{pr2}$

现在,您正在匹配字符组,由一个小写字母组成。不再返回o,因为这是一个贪婪的搜索,并且将返回最后一个有效的匹配组。因此,如果您将字符串更改为f233op12fre,则将返回最后的e,但不会返回前面的f或{}。同样,如果去掉字符串中的p,您仍然可以看到o作为有效匹配返回。在

相反,如果您试图通过添加?(例如([a-z])*?)使此正则表达式非贪心的,则返回的匹配集将全部为空字符串,因为有效的nothing匹配的优先级高于某个内容的有效匹配。在

例3

re.findall(r'([a-z]*)',"f233op")

匹配的字符没有什么不同,但是现在返回的是字符组而不是原始匹配。此regex查询的输出将与第一个示例相同,但您会注意到,如果添加其他匹配组,您将突然看到将每个匹配尝试分组为元组的结果:

IN : re.findall(r'([a-z]*)([0-9]*)',"f233op")
OUT: [('f', '233'), ('op', ''), ('', '')]  

与相同的模式进行对比,去掉括号(组),你就会明白为什么它们很重要:

IN : re.findall(r'[a-z]*[0-9]*',"f233op")
OUT: ['f233', 'op', ''] 

还有…

将这些regex模式插入到Regexplained等regex图生成器中,可以看到模式匹配逻辑是如何工作的。例如,为了解释regex为什么总是返回空字符串匹配,请看一下模式^{}和{a3}之间的区别。在

如果遇到问题,不要忘了检查Python docs for the ^{} library,它们实际上对标准regex语法给出了相当出色的解释。在

您的惊人结果与正则表达式量词*有关。在

考虑:

[a-z]*

Regular expression visualization

Debuggex Demo

对比:

^{pr2}$

Regular expression visualization

Debuggex Demo

作为另一个例子,我认为它更能说明你所看到的:

>>> re.findall(r'[a-z]*', '123456789')
['', '', '', '', '', '', '', '', '', '']

字符串123456789中的集合[a-z]中没有字符。然而,由于*的意思是'或更多',所有字符位置“匹配”的方式是不匹配该位置的任何字符。在

例如,假设您只想测试字符串中是否有字母,并使用如下正则表达式:

>>> re.search(r'[a-z]*', '1234')
<_sre.SRE_Match object at 0x1069b6988>     # a 'match' is returned, but this is 
                                           # probably not what was intended

现在考虑一下:

>>> re.findall(r'[a-z]*', '123abc789')
['', '', '', 'abc', '', '', '', '']

对比:

>>> re.findall(r'([a-z])*', '123abc789')
['', '', '', 'c', '', '', '', '']

第一个模式是[a-z]*。部分[a-z]是与集合a-z中的一个单个字符匹配的字符类,除非修改;如果大于零,则添加*量词将贪婪地匹配尽可能多的字符——因此匹配“abc”,但也允许零个字符匹配(或者字符集之外的字符匹配位置,因为0是匹配的)。在

([a-z])*中添加分组有效地将量化集中的匹配减少到单个字符,并返回集合中匹配的最后一个字符。在

如果您想获得分组的效果(比如在更复杂的模式中),请使用非捕获组:

>>> re.findall(r'(?:[a-z])*', '123abc789')
['', '', '', 'abc', '', '', '', '']
  1. 您得到了最后的'',因为[a-z]*与末尾的空字符串匹配。

  2. 缺少字符'o',因为您已经告诉re.findall匹配,并且每个组都有一个字符。换句话说,你做的相当于

    m = re.match(r'([a-z])*', 'op')
    m.group(1)
    

    它将返回'p',因为这是parens(捕获组1)捕获的最后一个内容。

  3. 同样,你是匹配组,但这次是多字符组。

相关问题 更多 >

    热门问题