百灵鸟语法:转义字符串正则表达式如何工作?
lark grammar: How does the escaped string regex work?
lark解析器预定义了一些常用的终端,包括字符串。定义如下:
_STRING_INNER: /.*?/
_STRING_ESC_INNER: _STRING_INNER /(?<!\)(\\)*?/
ESCAPED_STRING : "\"" _STRING_ESC_INNER "\""
我明白_STRING_INNER
。我也明白 ESCAPED_STRING
是如何组成的。但是我不太明白的是 _STRING_ESC_INNER
.
如果我正确阅读正则表达式,它只是说每当我发现两个连续的文字反斜杠时,它们前面不能有另一个文字反斜杠?
如何将这两个组合成一个正则表达式?
语法是否只允许在字符串数据中使用转义双引号?
预赛:
.*?
非贪婪匹配,意思是.
(任意符号)的尽可能短的重复次数。这只有在后面跟着其他东西时才有意义。因此 .*?X
输入 AAXAAX
将只匹配 AAX
部分,而不是一直扩展到最后 X
.
(?<!...)
是 "negative look-behind assertion" (link): "Matches if the current position in the string is not preceded by a match for ...."。所以 .*(?<!X)Y
会匹配 AY
但不会匹配 XY
.
将此应用于您的示例:
ESCAPED_STRING
:规则说:"Match "
, then _STRING_ESC_INNER
, and then "
again".
_STRING_INNER
:匹配任何符号的尽可能短的重复次数。如前所述,这仅在考虑其后的正则表达式时才有意义。
_STRING_ESC_INNER
:我们希望它匹配不包含右引号的最短字符串。也就是说,对于输入 "abc"xyz"
,我们希望匹配 "abc"
,而不是同时消耗 xyz"
部分。但是,我们必须确保 "
确实是一个结束引号,因为它本身不应该被转义。所以对于输入 "abc\"xyz"
,我们不想只匹配 "abc\"
,因为 \"
被转义了。我们观察到结束 "
必须直接在偶数 \
之前(零是偶数)。所以 "
可以,\"
可以,\\"
可以等等。但是只要 "
前面有奇数个 \
,这意味着"
并不是真正的收盘价。
(\\)
匹配 \
。 (?<!\)
表示 "the position before should not have \
"。所以合并 (?<!\)(\\)
意味着 "match \
, but only if it is not preceded by \
".
接下来的 *?
会尽可能重复此操作,这只有在考虑紧随其后的正则表达式时才有意义,即 [=20= 中的 "
] 规则(可能的混淆点:ESCAPED_STRING
中的 \"
指的是我们要匹配的实际输入中的文字 "
,与 \\
指的方式相同到输入中的 \
)。所以 (?<!\)(\\)*?\"
的意思是“匹配最短的 \
后跟 "
并且前面没有 \
。所以换句话说,(?<!\)(\\)*?\"
只匹配 "
前面有偶数个 \
(包括大小为 0 的块)。
现在将它与前面的 _STRING_INNER
结合起来,_STRING_ESC_INNER
规则然后说:匹配前面有偶数的 first "
\
的,所以换句话说,\
本身没有转义的第一个 "
。
lark解析器预定义了一些常用的终端,包括字符串。定义如下:
_STRING_INNER: /.*?/
_STRING_ESC_INNER: _STRING_INNER /(?<!\)(\\)*?/
ESCAPED_STRING : "\"" _STRING_ESC_INNER "\""
我明白_STRING_INNER
。我也明白 ESCAPED_STRING
是如何组成的。但是我不太明白的是 _STRING_ESC_INNER
.
如果我正确阅读正则表达式,它只是说每当我发现两个连续的文字反斜杠时,它们前面不能有另一个文字反斜杠?
如何将这两个组合成一个正则表达式?
语法是否只允许在字符串数据中使用转义双引号?
预赛:
.*?
非贪婪匹配,意思是.
(任意符号)的尽可能短的重复次数。这只有在后面跟着其他东西时才有意义。因此.*?X
输入AAXAAX
将只匹配AAX
部分,而不是一直扩展到最后X
.(?<!...)
是 "negative look-behind assertion" (link): "Matches if the current position in the string is not preceded by a match for ...."。所以.*(?<!X)Y
会匹配AY
但不会匹配XY
.
将此应用于您的示例:
ESCAPED_STRING
:规则说:"Match"
, then_STRING_ESC_INNER
, and then"
again"._STRING_INNER
:匹配任何符号的尽可能短的重复次数。如前所述,这仅在考虑其后的正则表达式时才有意义。_STRING_ESC_INNER
:我们希望它匹配不包含右引号的最短字符串。也就是说,对于输入"abc"xyz"
,我们希望匹配"abc"
,而不是同时消耗xyz"
部分。但是,我们必须确保"
确实是一个结束引号,因为它本身不应该被转义。所以对于输入"abc\"xyz"
,我们不想只匹配"abc\"
,因为\"
被转义了。我们观察到结束"
必须直接在偶数\
之前(零是偶数)。所以"
可以,\"
可以,\\"
可以等等。但是只要"
前面有奇数个\
,这意味着"
并不是真正的收盘价。(\\)
匹配\
。(?<!\)
表示 "the position before should not have\
"。所以合并(?<!\)(\\)
意味着 "match\
, but only if it is not preceded by\
".接下来的
*?
会尽可能重复此操作,这只有在考虑紧随其后的正则表达式时才有意义,即 [=20= 中的"
] 规则(可能的混淆点:ESCAPED_STRING
中的\"
指的是我们要匹配的实际输入中的文字"
,与\\
指的方式相同到输入中的\
)。所以(?<!\)(\\)*?\"
的意思是“匹配最短的\
后跟"
并且前面没有\
。所以换句话说,(?<!\)(\\)*?\"
只匹配"
前面有偶数个\
(包括大小为 0 的块)。现在将它与前面的
_STRING_INNER
结合起来,_STRING_ESC_INNER
规则然后说:匹配前面有偶数的 first"
\
的,所以换句话说,\
本身没有转义的第一个"
。