Python 正则表达式模块使用 BRE 还是 ERE?

Does the Python regular expression module use BRE or ERE?

看来 POSIX 将正则表达式的实现分为两种:基本正则表达式 (BRE) 和扩展正则表达式 (ERE)。

Python re module参考好像没有说明。

除了语法上的一些相似性,re 模块 不遵循 POSIX 正则表达式标准 .

不同的匹配语义

POSIX 正则表达式(可以用 DFA/NFA 甚至回溯引擎实现)总是找到 最左边的最长匹配 ,而 re模块是一个回溯引擎,它找到最左边的"earliest"匹配("earliest"根据正则表达式定义的搜索顺序)。

在匹配 (Prefix|PrefixSuffix)PrefixSuffix 的情况下可以观察到匹配语义的差异。

  • 在 POSIX-complaint 实现 POSIX 正则表达式(不是那些只借用语法的)中,正则表达式将匹配 PrefixSuffix.
  • 相比之下,re 引擎(以及许多其他回溯正则表达式引擎)将仅匹配 Prefix,因为 Prefix 在交替中首先指定。

在匹配 (xxx|xxxxx)*xxxxxxxxxx 的情况下也可以看出差异(10 个 x 的字符串):

  • 在 Cygwin 上:

    $ [[ "xxxxxxxxxx" =~ (xxx|xxxxx)* ]] && echo "${BASH_REMATCH[0]}"
    xxxxxxxxxx
    

    全部 10 x 个匹配。

  • 在Python:

    >>> re.search(r'(?:xxx|xxxxx)*', 'xxxxxxxxxxx').group(0)
    'xxxxxxxxx'
    

    只有 9 个 x 匹配,因为它在所有 3 次重复中交替选择第一个项目 xxx,并且没有任何强制它回溯并交替尝试第二个项目)

POSIX-独家正则表达式功能

除了匹配语义的不同,POSIX正则表达式还定义了比较符号等价class表达式的语法,以及 基于排序规则的字符范围 。这些特性大大增加了正则表达式的表达能力。

以等价class表达式为例,来自文档:

An equivalence class expression shall represent the set of collating elements belonging to an equivalence class, as described in Collation Order. [...]. The class shall be expressed by enclosing any one of the collating elements in the equivalence class within bracket-equal ( "[=" and "=]" ) delimiters. For example, if 'a', 'à', and 'â' belong to the same equivalence class, then "[[=a=]b]", "[[=à=]b]", and "[[=â=]b]" are each equivalent to "[aàâb]". [...]

由于这些功能在很大程度上取决于语言环境设置,因此相同的正则表达式在不同的语言环境中可能表现不同。它还取决于系统上的区域设置数据的整理顺序。

re 正则表达式特征

re 借鉴了 Perl 的语法,但并非 Perl 正则表达式中的所有功能都在 re 中实现。以下是 re 中可用的一些正则表达式功能,这些功能在 POSIX 正则表达式中不可用:

  • Greedy/lazy量词,指定展开量词的顺序。

    虽然人们通常称POSIX中的*是贪婪的,但它实际上只是规定了POSIX中重复的下界和上界。所谓"greedy"行为是由于最左最长匹配规则。

  • 环视断言(前瞻和后视)
  • 条件模式(?(id/name)yes-pattern|no-pattern)
  • 速记结构:\b\s\d\w(某些 POSIX 正则表达式引擎可能会实现这些,因为标准对于这些情况,行为未定义)

都没有。它基本上是 PCRE 方言,但有不同的实现。

re 文档中的第一句话说:

This module provides regular expression matching operations similar to those found in Perl.

虽然这不会立即向新来者揭示他们与例如POSIX 正则表达式,众所周知,Perl 4 和后来的 Perl 5 提供了比早期工具的正则表达式功能大幅扩展的功能集,包括 POSIX 为 grep -E 授权的又名 ERE .

perlre manual page 更详细地描述了正则表达式的功能,尽管您会在 Python 文档中以不同的形式找到很多相同的详细信息。 Perl 手册页包含这段历史:

The patterns used in Perl pattern matching evolved from those supplied in the Version 8 regex routines. (The routines are derived (distantly) from Henry Spencer's freely redistributable reimplementation of the V8 routines.)

(这里V8指的是Version 8 Unix. Spencer's library basically (re)implemented POSIX regular expressions。)

Perl 4 有大量方便的结构,如 \d\s\w 以及符号速记,如 \t\f\n。 Perl 5 添加了一组重要的扩展(仍在缓慢增长),包括但不限于

  • 非贪婪量词
  • 非回溯量词
  • Unicode 符号和 属性 支持
  • 非分组括号
  • 先行和后行
  • ...基本上任何以 (?
  • 开头的东西

因此,"regular" 表达式不再是严格的 "regular"。

这由 Philip Hazell 在便携式库中重新实现,最初用于 Exim 邮件服务器;他的 PCRE library 已经进入无数不同的应用程序,包括许多编程语言(Ruby、PHP、Python 等)。顺便说一句,尽管名称如此,但该库并不是严格意义上的 "Perl compatible"(不再);在功能和行为上都有差异。 (例如,Perl 在内部将 * 更改为 {0,32767} 之类的东西,而 PCRE 会做其他事情。)

Python 的早期版本实际上有一个不同的正则表达式实现,并且有 plans to change it again(尽管它基本上仍然是 PCRE)。这是 Python 2.7 / 3.5 的情况。