我偶然发现了 Apple 的 awk 关于等价类的奇怪行为,所以我试图了解正则表达式解析器的细节:
绳子 | 正则表达式 |
|
---|---|---|
|
|
awk:非终止字符类 |
|
|
|
|
|
awk:非终止字符类 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
awk:语法错误 |
是否可以伪造一个多平台测试(BSD、Apple、GNU、POSIX)来确定正则表达式引擎是否已损坏,而不造成
awk
崩溃?
旁白: 用于测试的示例代码(第一行):
awk 'BEGIN{
string="anything"; regexp="[[=a]";
gsub(regexp, "_", string); print string
}'
源代码显示,当解析器在括号表达式中遇到
[.
或[=
时,它会消耗[.
或[=
之后的一个字符(可以是多字节)并检查匹配
.]
或 =]
:
此外(幸运的是),BSD 的解析器在
[:
或 [.
内时不会转换反斜杠转义序列;我们可以“利用”这个事实,并使用例如 \t
,这是在 [:
或 [.
内部使用的合法转义序列,来表征此特定实现:
# BSD awk (macOS and FreeBSD)
awk 'BEGIN { print match("\t", /[[=\t=]]/) }'
0
# GNU awk
awk 'BEGIN { print match("\t", /[[=\t=]]/) }'
1
# Solaris XPG4 awk
command -p awk 'BEGIN { print match("\t", /[[=\t=]]/) }'
1
[[=\t=]]
发生的情况是:
[
被消耗,解析器被置于 inside-bracket-expression 状态。[=
被消耗,解析器获取下一个字符,即 \
t
=
)处获取“峰值”,并将它们与 =
]
进行比较。由于它们不匹配,解析器返回到 inside-bracket-expression 状态,并且对之前的 \
(错误)不执行任何操作。t
被消耗并添加括号表达式的字符列表。=
被消耗了,我不知道为什么解析器不做任何事情?]
被消耗,解析器进入 outside-bracket-expression 状态。]
被消耗并连接到前面的括号表达式。考虑到这些步骤,另一个可行的测试是:
# BSD awk (macOS and FreeBSD)
awk 'BEGIN { print match("t]", /[[=\t=]]/) }'
1
# GNU awk
awk 'BEGIN { print match("t]", /[[=\t=]]/) }'
0
# Solaris XPG4 awk
command -p awk 'BEGIN { print match("t]", /[[=\t=]]/) }'
0