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

fdbelqdn  于 2023-03-31  发布在  Python
关注(0)|答案(2)|浏览(163)

POSIX似乎将正则表达式实现分为两种:基本正则表达式(BRE)和扩展正则表达式(ERE)。
Python re module参考似乎没有指定。

7gs2gvoe

7gs2gvoe1#

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

匹配语义不同

POSIX正则表达式(可以用DFA/NFA甚至回溯引擎实现)总是找到最左边的最长匹配,而re模块是一个回溯引擎,它找到最左边的“最早”匹配(根据正则表达式定义的搜索顺序,“最早”)。
在匹配(Prefix|PrefixSuffix)PrefixSuffix的情况下,可以观察到匹配语义的差异。

  • 在POSIX正则表达式的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正则表达式除了在匹配语义上的差异外,还定义了排序符号等价类表达式基于排序的字符范围的语法,这些特性极大地增强了正则表达式的表达能力。
以等价类表达式为例,来自文档:
等价类表达式应表示属于等价类的排序元素的集合,如排序顺序中所述。[...]。该类应通过将等价类中的任何一个排序元素包含在括号-equal中来表示("[=""=]")分隔符。例如,如果'a''à''â'属于同一等价类,则"[[=a=]b]""[[=à=]b]"、和"[[=â=]b]"各自等价于"[aàâb]"。[...]
由于这些特性很大程度上依赖于语言环境设置,因此同一个正则表达式在不同的语言环境下可能会有不同的行为。它还依赖于系统上的语言环境数据来确定排序规则。

re正则表达式特性

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

  • Greedy/lazy限定符,它指定展开限定符的顺序。

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

  • Look-around assertion(look-ahead和look-behind)
  • 条件模式(?(id/name)yes-pattern|no-pattern)
  • 短臂结构:\b\s\d\w(一些POSIX正则表达式引擎可能实现这些,因为标准未定义这些情况的行为)
oaxa6hgo

oaxa6hgo2#

两者都不是。它基本上是PCRE方言,但它是一个不同的实现。
re文档中的第一句话是:
该模块提供了与Perl中的操作类似的正则表达式匹配操作。
虽然这并不能立即向新手揭示它们与POSIX正则表达式的关系,但应该知道Perl 4和后来的Perl 5提供了比早期工具的正则表达式功能更丰富的功能集,包括POSIX对grep -E(又名ERE)的强制要求。
perlre manual page更详细地描述了正则表达式的特性,尽管你会在Python文档中以不同的形式找到相同的细节。Perl手册页包含了这段历史:
Perl模式匹配中使用的模式是从Version 8 regex例程中提供的那些模式发展而来的(这些例程是从亨利Spencer对V8例程的可自由再分发的重新实现中派生出来的)。
(Here Spencer的库基本上(重新)实现了POSIX正则表达式。)
Perl 4有大量的方便结构,如\d\s\w以及符号简写,如\t\f\n。Perl 5添加了一组重要的扩展(仍在缓慢增长),包括但不限于:

  • 非贪婪量词
  • 非回溯量词
  • Unicode符号和属性支持
  • 非分组括号
  • 前瞻与前瞻
  • ...基本上任何以(?开头的内容

因此,“正则”表达式不再是严格的“正则”表达式。
这是由Philip Hazel在一个可移植库中重新实现的,最初是为Exim邮件服务器;他的PCRE library已经在无数不同的应用程序中找到了自己的方式,包括许多编程语言(Ruby、PHP、Python等)。在特性和行为上都有区别。(例如,Perl在内部将*更改为类似{0,32767}的东西,而PCRE则执行其他操作。)
Python的早期版本实际上有一个不同的正则表达式实现,有plans to change it again(尽管它基本上仍然是PCRE)。这是Python 2.7 / 3.5的情况。

相关问题