对re.compile行为感到困惑

时间:2015-01-04 00:59:35

标签: python regex

请帮助我理解为什么CODE2中的代码有效。我的理解是re.compile返回一个对象,我们指定searchmatchfindall等方法来获得所需的结果。

我感到困惑的是re模块级函数如搜索如何能够接受编译的abject作为参数。请参阅CODE2

CODE1:

In [430]: p = re.compile(r'(\b\w+)\s+\1')
In [431]: p.search('Paris in the the spring').group()
Out[431]:
'the the'

CODE 2

In [432]: re.search(p, 'Paris in the the spring').group()
Out[432]:
'the the'

2 个答案:

答案 0 :(得分:3)

re.search的第一个参数被记录为重新模式字符串,即编译的RE对象 - 也许更好的设计会有在re模块正在开发的时候,我已经接受了多态,但是,唉!,这不是我们怎么做的。好吧,至少在re中模仿re编译对象方法的所有模块函数都是一样的! - )

然而,在Python漫长而传奇的历史中,有人修复了我们原来的错误设计(我不能说发生了什么事!):现在,对于大多数{{1}函数第一个re参数仍然被认为必须是RE模式字符串,现在有一些被记录为“可能是字符串或RE对象”......和所有他们似乎工作(更好!)的方式。

因此,如果你有一个编译好的pattern理论,根据(大多数)文档,你需要调用它的方法(它通常是最好的方法,除了最短的片段)而不是将其传递给re模块级函数,例如re。但在实践中,编译的re.search对象将与记录的RE模式一样精细。

男人,好的事情,当我开始准备(与两位共同作者)第三版“果壳中的Python”时,我意识到这一点......至少我会“修复文档”的! - )

补充:为了衡量速度,像往常一样,re是你的朋友!

timeit

$ python -mtimeit -s'import re; s="paris in the spring"; mre=re.compile("paris")' 're.match("paris", s)'
1000000 loops, best of 3: 1.38 usec per loop

因此,总的来说,通过$ python -mtimeit -s'import re; s="paris in the spring"; mre=re.compile("paris")' 'mre.match(s)' 1000000 loops, best of 3: 0.468 usec per loop 一次事件,你可以比re.compile函数为你处理所有事情快3倍。看看为什么我喜欢re方法? - )

此外,在Python中,“更快”倾向于与“更多Pythonic”(换句话说,“Python中的惯用语”)强烈相关。如果你不确定哪两个接近Pythonic,re.compile它们是正确的(最好使用命令行方法timeit),如果任何一种方法可靠得快,你就得到了答案:那种方法更像Pythonic! - )

答案 1 :(得分:1)

re模块中的所有函数都允许您指定模式对象而不是模式字符串。它只是一个优化/便利功能,允许您避免构建新的模式对象(如果已有)。


我无法找到明确提及此行为的文档链接,但如果您查看源代码 1 ,则可以很容易地看到它。首先,re.compile的{​​{3}}为:

def compile(pattern, flags=0):
    "Compile a regular expression pattern, returning a pattern object."
    return _compile(pattern, flags)

注意这个函数除了调用另一个名为_compile的函数之外什么都不做。这个函数实际上构建了一个模式对象。 re.compile只是它的别名。


继续前进,re.search的{​​{3}}为:

def search(pattern, string, flags=0):
    """Scan through string looking for a match to the pattern, returning
    a match object, or None if no match was found."""
    return _compile(pattern, flags).search(string)

正如您所看到的,re.search函数也没有什么特别之处。它只调用search返回的模式对象的re._compile方法。这意味着:

re.search(p, 'Paris in the the spring').group()

与:

相同
re._compile(p).search('Paris in the the spring').group()

所以你应该问的问题是为什么re._compile允许你将模式对象作为模式字符串传递。和以前一样,通过查看implementation

可以找到答案
def _compile(pattern, flags):
    ...
    if isinstance(pattern, _pattern_type):
        if flags:
            raise ValueError(
                "Cannot process flags argument with a compiled pattern")
        return pattern

如您所见,_compile函数检查其pattern参数是否已经是模式对象。如果是这样,它只是返回它并避免构建一个新的。这意味着:

re.search(p, 'Paris in the the spring').group()

相当于:

re._compile(p).search('Paris in the the spring').group()

变为:

p.search('Paris in the the spring').group()

1 这是CPython的源代码。