标准正则表达式与python正则表达式差异

时间:2010-01-12 14:38:20

标签: python regex theory

我正在读一本书,他们提供了一个如何将给定字符串与正则表达式匹配的示例。 这是他们的例子:

b*(abb*)*(a|∊) - Strings of a's and b's with no consecutive a's.

现在我尝试将其转换为python:

>> p = re.compile(r'b*(abb*)*(a|)') # OR
>> p = re.compile(r'b*(abb*)*(a|\b)')

# BUT it still doesn't work
>>> p.match('aa')
<_sre.SRE_Match object at 0x7fd9ad028c68>

我的问题是双重的:

  1. 在python中使用epsilon相当于使上面的例子有效吗?
  2. 有人可以向我解释为什么理论或标准的正则表达式在python中不起作用?它可能与最长匹配和最短匹配有关吗?
  3. 澄清:对于那些询问标准正则表达式的人来说 - 它是形式语言理论标准:http://en.wikipedia.org/wiki/Regular_expression#Formal_language_theory

7 个答案:

答案 0 :(得分:5)

实际上,这个例子对于一个小细节来说效果很好。我会写:

>>> p = re.compile('b*(abb*)*a?')
>>> m = p.match('aa')
>>> print m.group(0)
'a'
>>> m = p.match('abbabbabababbabbbbbaaaaa')
>>> print m.group(0)
abbabbabababbabbbbba

请注意,组0返回正则表达式匹配的字符串部分。

正如您所看到的,表达式匹配a和b的连续而不重复a。如果确实想要检查整个字符串,则需要稍微更改一下:

>>> p = re.compile('^b*(abb*)*a?$')
>>> m = p.match('aa')
>>> print m
None

^$强制识别字符串的开头和结尾。

最后,您可以使用第一个正则表达式组合这两种方法,但最后进行测试:

>>> len(m.group(0)) == len('aa')

已添加:对于OT的第二部分,在我看来标准正则表达式和python实现之间没有差异。当然,符号略有不同,python实现提出了一些扩展(与大多数其他包一样)。

答案 1 :(得分:5)

感谢您的回答。我觉得每个答案都有答案的一部分。这就是我要找的东西。

  1. 符号只是(某事|ε)的简写。因此,(a |ε)可以重写为 a?。所以这个例子就变成了:

    b*(abb*)*a?
    

    在python中我们会写:

    p = re.compile(r'^b*(abb*)*a?$')
    
  2. 将常规正则表达式语法直接转换为python(即复制和粘贴)不起作用的原因是因为python匹配最短子串(如果符号$或^不存在)而理论正则表达式匹配最长的初始子串
    例如,如果我们有一个字符串:

    s = 'aa'
    

    我们的教科书正则表达式 b *(abb *)* a?与它不匹配,因为它有两个a。但是如果我们直接将它复制到python:

    >> p = re.compile(r'b*(abb*)*a?')
    >> bool(p.match(s))
    True
    

    这是因为我们的正则表达式只匹配字符串'aa'的子字符串'a'。
    为了告诉python在整个字符串上进行匹配,我们必须告诉它字符串的开头和结尾分别是 ^ $ 符号:

    >> p = re.compile(r'^b*(abb*)*a?$')
    >> bool(p.match(s))
    False
    

    请注意,python regex match()匹配字符串的开头,因此它会在开始时自动采用 ^ 。但是 search()功能没有,因此我们保留 ^
     例如:

    >> s = 'aa'
    >> p = re.compile(r'b*(abb*)*a?$')
    >> bool(p.match(s))
    False                 # Correct
    >> bool(p.search(s))
    True                  # Incorrect - search ignored the first 'a'
    

答案 2 :(得分:3)

1

  • 使用bool(p.match('aa'))检查正则表达式是否匹配

  • p = re.compile('b*(abb*)*a?$')

  • \b匹配字符串的边框; \w\W之间的位置(单词字符和非单词字符)

2

Regexp在python中非常标准。然而,每种语言都有一些风格,它们不是100%便携的。在使用任何特定语言的regexp之前,您需要查找的细微差别。

<强>加成

\epsilon在python中没有特殊符号。这是一个空字符集。

在您的示例中,a|\epsilon相当于(a|)a?。之后$必须匹配字符串的结尾。

答案 3 :(得分:3)

我不确定python中的匹配是如何工作的,但我认为您可能需要将^ .... $添加到您的RE中。 RegExp匹配通常匹配子字符串,并且它找到最大匹配,在p.match('aa')的情况下,它是“a”(可能是第一个)。 ^ ... $确保你匹配整个字符串,我相信你想要的。

理论/标准reg exps假设你总是匹配整个字符串,因为你用它来定义匹配的字符串语言,而不是在输入字符串中找到子字符串。

答案 4 :(得分:1)

您正在匹配,因为您的正则表达式匹配任何标本文本的任何零宽度段。你需要锚定你的正则表达式。这是使用零宽度前瞻断言的一种方法:

re.compile(r'^(a(?!a)|b)*$')

答案 5 :(得分:1)

尽管我以前从未在正则表达式中看过epsilon,但你的第二个应该是epsilon的合适替代品。

对于它的价值,你的模式匹配'a'。也就是说,它匹配:

  • 零或更多“b”s(选择零)
  • 零或更多“(abb*)”s(选择零)
  • 一个“a”或单词结尾(选择a)。

正如Jonathan Feinberg所指出的,如果你想确保整个字符串匹配,你必须锚定你的正则表达式的开头('^')和结束('$')。每当在python中构造正则表达式时,你也应该使用原始字符串:r'my regex'。这样可以防止过多的反斜杠逃避混乱。

答案 6 :(得分:1)

表达式的问题在于它与空字符串匹配,这意味着如果你这样做:

>>> p = re.compile('b*(abb*)*(a|)')
>>> p.match('c').group(0)
''

并且由于re.match尝试匹配字符串的开头,因此必须告诉它匹配它直到字符串的结尾。只需使用$即可获得

>>> p = re.compile(r'b*(abb*)*(a|)$')
>>> print p.match('c')
None
>>> p.match('ababababab').group(0)
'ababababab'

ps-您可能已经注意到我在here(第一段)上使用了r'pattern'而不​​是'pattern'