正则表达式的不同风格:BRE、ERE、PCRE

写这篇文章的原因是,我在VScode上熟练使用正则表达式,但是当我在 grepfindvim 等工具中使用正则表达式时,往往会遇到各种问题。即便在 VSCode 上正常工作的正则表达式,在这些工具中却突然失效,甚至报错,这让我感到非常困惑。直到今天,我才意识到这些问题是因为 grep 等工具的正则表达式实现与 VSCode 所用的正则表达式标准不同导致的。

正则表达式分类

在Linux中,正则表达式主要有三种类型:

  • 基本正则表达式(Basic Regular Expression,BRE)
  • 扩展正则表达式(Extended Eegular Expression,ERE)
  • Perl兼容正则表达式(Perl-Compatible Regular Expression,PCRE)

BREERE可以进一步分为POSIX BRE/EREGNU BRE/ERE

在详细了解每种类型之前,先了解它们的起源和为什么存在多种正则表达式类型。

最初,BRE定义了一系列元字符,例如星号和方括号,以在模式匹配的上下文中具有特殊含义。后来,ERE扩展了这个想法,加入了更多的元字符,以允许更灵活的匹配模式。这两种类型随后在POSIX标准中进行了规范化。

后来,GNU项目在POSIX BRE和ERE的基础上进行了扩展,以进一步增强其命令行工具,如grep、gawk和sed。由于这些扩展不符合POSIX的定义,因此它们被称为GNU BRE和GNU ERE。

最后,PCRE是正则表达式的后续版本,包含了更高级的功能。PCRE是PHP、Java和JavaScript等语言中最常采用的标准,尽管其实现通常不完全遵循规范,并且存在一些小的变动。

从集合的角度来看,POSIX BRE的功能是POSIX ERE的一个子集,而POSIX ERE又是GNU BRE和ERE的一个子集。在所有类型中,PCRE是所有类型的超集。

regex- family

POSIX BREERE

POSIX BRE 被认为是仍在使用的最古老的正则表达式类型。因此,它具有最基本的模式匹配运算符集。具体来说,POSIX BRE 支持.^$*{})量词,以及字符集表达式(bracket expression)。

POSIX ERE对这些运算符进行了扩展,POSIX ERE 还支持通过管道符号(|)进行选择。POSIX ERE 还定义了加号(+)和问号(?)量词,以支持匹配 1 个或多个以及 0 个或 1 个的模式。

BRE 的一个显著特点是反斜杠(\)必须位于某些元字符之前,以使它们具有特殊含义。具体而言,像 {}() 这样的元字符在没有反斜杠的情况下失去了它们的特殊含义。这与 ERE 不同,在 ERE 中,前置反斜杠使这些元字符失去特殊含义。

GNU BREERE

GNU BREGNU ERE 是在 POSIX BREERE之上的扩展。这意味着 GNU BREERE 能够处理 POSIX 等效的所有功能及更多功能。此外,GNU BRE 在功能上与 GNU ERE 相同,因为它们定义了一组相同的功能,不同于 GNU 的。

它们唯一的区别是 GNU BRE 需要使用反斜杠字符来赋予与 GNU BRE 相同的一组元字符特殊含义。例如在GNU BRE中使用+运算符需要添加\+才会生效。

简单来说就是:在EREPCRE中,可以直接使用*, +, ?, (, ), {, }, |, .这些字符,但在BRE中,需要在前面加上转义符\*, \+, \?, \(, \), \{, \}, |, \.

单词边界

除了所有 POSIX 功能,GNU BRE 和 ERE 还包括对单词边界的支持,使用 \b\B\<\> 操作符。具体来说,\b 操作符指定单词的开始或结束,而 \B\b 的取反版本。例如,假设我们有一个包含2行的 word-boundary.txt 文件:

$ cat word-boundary.txt
brownpancakes
brown pancakes

我们可以通过匹配带有单词边界的 brown 来选择第二行:

$ cat word-boundary.txt | grep -E "brown\b"
brown pancakes

另一方面,我们可以使用 \B 来选择不带单词边界的第一行:

$ cat word-boundary.txt | grep -E "brown\B"
brownpancakes

此外,还有两个操作符允许我们准确匹配单词的开始或结束。具体来说,\< 操作符专门匹配单词的开始,\> 操作符匹配单词的结束。

简写

此外,GNU 扩展还支持简写类,例如 \w\s,提供了常用字符类的简洁语法。具体来说,我们可以使用 \w 语法来匹配任何字母数字值,它等同于 POSIX 的方括号语法 [a-zA-Z0-9_]

类似地,\s 语法是匹配空格、制表符、回车符、换行符或换页符的简写,等同于 [ \t\r\n\f]

PCRE

PCRE 是在本文章中提到的不同正则表达式标准中功能最完整的标准。事实上,现在流行的正则表达式引擎通常实现了 PCRE 标准的变体,以提供更完整的正则表达式体验。让我们看看 PCRE 的一些附加功能。

先行断言和后行断言

断言操作符是一个强大的正则表达式功能。它有两种变体:先行断言和后行断言语法。对于先行断言,有正向和负向版本,以允许取反表达式。例如,我们可以写一个正向先行断言表达式来匹配文本 brown 后跟 fox,而不考虑 fox 作为匹配项:

brown(?=fox)

另一方面,为了匹配 brown 后面没有 fish 这个单词的文本,我们可以使用负向先行断言表达式:

brown(?!fish)

要向后匹配,我们使用后行断言。为了使表达式匹配前面有 brownfox 文本,我们可以使用正向后行断言语法:

(?<=brown)fox

类似地,我们可以使用负向后行断言匹配文本 fish,紧跟在单词 brown 之后:

(?<!brown)fish

没有先行和后行断言语法,我们只能将整个 brownfish 作为匹配项,而不仅仅是单词 brown

懒惰修饰

默认情况下,所有量词(如 ?*{n,})都是贪婪的。换句话说,它们会消耗尽可能多的匹配项。考虑一个字符串:

goooooo

go+go*go{1,} 这样的表达式在匹配目标时是贪婪的。具体来说,这些表达式会匹配整个 “goooooo” 文本,尽管它们只需要一个 “o” 在 “g” 字符之后。通过应用懒惰修饰符,我们可以使这些表达式消耗它们所需的最少标记。具体来说,这些表达式的“懒惰”等价形式是 go+?go*?go{1,}?

总结

Vscode默认使用PCRE

vim默认使用BRE,搜索框输入\v后接正则表达式,启用ERE

grep默认使用BRE,grep -E启用ERE,grep -P启用PCRE

find默认使用BRE,find -regex启用ERE

用法参考:终于明白vim 和 grep 中 的正则表达式的用法, vim 正则表达式 和grep基本正则表达式 几乎一样

对于不同的语法:只要知道大概就可以了,没有必要深入纠结,因为在不同的系统和不同的软件版本下,具体是使用那种正则表达式规则,谁也说不清楚,只有通过查看源代码才能得知,例如grep也不是严格的BRE语法,grep无论是否添加-E都能支持\w运算符。

作者:WuQiling
文章链接:https://www.wqlblog.cn/正则表达式的不同风格:bre、ere、pcre/
文章采用 CC BY-NC-SA 4.0 协议进行许可,转载请遵循协议
暂无评论

发送评论 编辑评论


				
默认
贴吧
上一篇
下一篇