我正在阅读《灵活性软件设计 (SDF)》。练习 2.10 要求实现BRE 和 ERE 的翻译器。本书使用像 ERE 中grep
那样测试翻译的字符串(a.c)
来捕获类似abc
或 的内容adc
。
我使用 Arch Linux。
根据POSIX 规范9.3.3 BRE 特殊字符,\+
不受 BRE 支持。
但是man grep
“基本与扩展正则表达式”允许\+
使用默认选项 BRE。
BRE 对应于 ed 或historical grep 类型
不过ed
好像也支持\+
。
(已编辑:此段内容有误,因为启用选项 b 时,该网站根本不符合 BRE。(ab)
而不是\(ab\)
将匹配“ab”。)https://www.regexplanet.com/advanced/postgresql/index.html可以支持单纯的 BRE,但它有点慢,并且不能轻易地合并到 Scheme 代码中(我正在学习 SICP 和 SDF,所以我没有检查 Scheme 中的 Http 实现。上面的书使用 shell 来运行grep
)。我使用表达式a\+c
和输入abc
在启用选项 b 的情况下进行测试。它显示“regex_matches()”为“(none)”。
那么是否有一个正则表达式工具完全遵循BRE?
POSIX 定义了一些字符,称为元字符或“特殊字符”,它们在正则表达式中使用时具有非文字含义,例如
.
匹配任何字符。POSIX 还定义了在这样的元字符前放置反斜杠时会发生什么\
,即它变为文字,因此\.
匹配文字.
字符。s
例如(或在 BRE 中),不是此类元字符的字符+
称为“普通字符”。POSIX 对普通字符的定义如下(重点是我的):即,它没有明确定义当你
\
在普通字符前面放置一个时会发生什么(除了上面提到的几个),这就是为什么工具可以定义为与该工具\s
相同的含义并且仍然符合 POSIX 标准,因为任何工具都可以根据输入做任何它喜欢的事情,以至于 POSIX 没有定义如何处理该输入。[[:space:]]
关于:
大多数(全部?)
grep
和sed
实现默认都是这样的,但是像我认为您希望的那样,仅实现 POSIX 定义的行为的工具根本就不可能存在,因为 POSIX 故意没有定义所有内容(POSIX 描述了大多数工具在大多数情况下都具有的通用功能,它并没有规定所有工具在所有情况下必须如何表现),因此,无论谁实现任何版本的任何工具,都必须自己决定当该工具遇到某些未由 POSIX 定义的输入时该做什么 - 实现一些他们认为有用的功能,将其视为文字字符,打印警告消息,删除所有文件,损坏硬盘或任何其他他们认为合适的操作。只要它们实现了 POSIX 定义的功能,那么该工具就是符合 POSIX 的,无论它在未定义的情况下做什么。假设汽车有这样一条标准:“当驾驶员将方向盘向右转动时,汽车向右转”。汽车制造商应该遵守该要求。该标准可能没有定义当您将方向盘拉向自己时会发生什么,因此如果日产决定,如果您在 2015 年的 Maxima 中这样做,那么汽车就会起飞并开始飞行或压缩成一个小立方体,这仍然符合标准。同样,POSIX 定义了
.
、s
和的\.
含义,但 POSIX 没有定义\s
含义,因此 GNU 可以定义\s
为等同于[[:space:]]
或任何他们喜欢的内容,同时仍然符合 POSIX 标准。因此,如果您希望正则表达式在所有版本的工具中都具有相同的行为(例如
grep
按照 POSIX 定义的方式),那么就不要编写依赖于 POSIX 未定义行为的正则表达式。这包括不在\+
BRE 中编写,不在 BRE 或 ERE 中编写\s
,这样,grep
在处理该正则表达式时,您使用的任何内容都将符合适用的 POSIX 标准。POSIX 正则表达式、BRE 和 ERE 是在POSIX 标准中定义的,不在任何给定工具的手册页中,而且肯定也不在 regex101.com 上,据我所知,该网站没有处理 POSIX BRE 或 ERE 的选项。
关于评论中设置的建议
POSIXLY_CORRECT
:POSIXLY_CORRECT
仅适用于 GNU 工具,因此它对 BSD 等工具没有帮助,并且即使在 GNU 中,它的作用也因工具而异,例如在设置了 POSIXLY_CORRECT 的 GNU awk 中,它会报告为\s
未定义的行为并将其视为正则表达式s
中的文字,而在 GNU grep 中,无论是否设置了 POSIXLY_CORRECT,它都会以相同的方式处理\s
(和\+
)。例如: