Lua 没有传统的正则表达式语言,它有 Lua 模式。虽然它们看起来很像正则表达式,但 Lua 模式是一种独特的语言,具有更简单的规则集,最重要的是缺乏分组和交替功能。
解释为 Lua 模式,该示例将使长期使用正则表达式的用户感到惊讶,因为许多细节都不同。
Lua 模式是describedinPiL,乍一看与传统的正则表达式非常相似,会引起混淆。最大的区别可能是缺少交替运算符|,括号仅用于标记捕获,量词(?、-、+ 和*)仅适用于字符或字符类, 而% 是转义字符而不是\。这个例子可能没有考虑到 Lua 编写的一个重要线索是缺少 Lua 模式引用字符 % 应用于模式字符串中的任何(或理想情况下,所有)非字母数字字符,以及可疑的使用的 \? 闻起来像一个传统的正则表达式来匹配单个文字 ?。
对所提问题的简单回答是:(^?)* 不是推荐的形式,它会匹配 ^* 或 *,捕获插入符号的存在或不存在。如果这是预期的效果,那么我会将其写为(%^?)%* 以使其更清晰。
要了解为什么会出现这种情况,让我们将给出的模式作为 Lua 模式进行分析。整个模式是:
^(^?)*\?(.*)$
交给string.match(),会这样解释:
^ 将匹配锚定到字符串的开头。
( 标志着第一次捕获的开始。
^ 不在模式或字符类的开头,因此它匹配文字 ^ 字符。为了清楚起见,应该写成%^。
? 完全匹配前一个字符的零个或一个。
) 标志着第一次捕获的结束。
* 不是在可以量化的东西之后,因此它与文字 * 字符匹配。为了清楚起见,应该写成%*。
\ 在模式中匹配自身,它不是模式语言中的转义字符。但是,它 是 Lua 短字符串文字中的转义字符,使得后面的字符对于字符串文字解析器来说不是特殊的,在这种情况下它是没有实际意义的,因为后面的 ? 对它来说并不特殊在任何情况下。因此,如果模式用双引号或单引号括起来,那么 \ 将被字符串解析所吸收。如果写成长字符串(如[[^(^?)*\?(.*)$]],反斜杠将在字符串解析器中保留下来,出现在模式中。
? 完全匹配前一个字符的零个或一个。
( 标志着第二次捕获的开始。
. 完全匹配任何字符,实际上是 [\000-\255] 类的同义词(请记住,在 Lua 中,数字转义是十进制而不是 C 中的八进制)。
* 贪婪地匹配前一个字符的零个或多个。
) 标志着第二次捕获的结束。
$ 将模式锚定到字符串的末尾。
因此它匹配并捕获字符串开头的可选^,然后是*,然后是未捕获的可选\,并捕获整个字符串的其余部分。 string.match 将在成功时返回两个字符串(其中一个或两个都可能是零长度),或者在失败时返回 nil。
编辑:我修正了一些拼写错误,并更正了我的回答中的一个错误,Egor 在评论中注意到了这一点。我忘记了在模式中,特殊符号在无法应用的地方失去了它们的特殊性。这使得第一个星号匹配文字星号而不是错误。大部分答案都是级联的。
请注意,如果您真的想要在 Lua 中使用真正的正则表达式,可以使用一些库来提供它。也就是说,内置的模式语言非常强大。如果这还不够,那么您最好采用完整的解析器,并使用LPeg,它可以做正则表达式所能做的一切,甚至更多。它甚至还附带一个模块,该模块提供完整的正则表达式语法,该语法被翻译成 LPeg 语法以供执行。