在这个正则表达式中,(^?)*代表什么意思?

19

我有这个正则表达式:

^(^?)*\?(.*)$

如果我理解正确,这是它的功能分解:
  • ^ - 从字符串开头开始匹配
  • (^?)* - 我不知道,但它将其存储在$1中
  • \? - 匹配问号
  • (.*)$ - 匹配直到字符串结尾的任何内容
那么(^?)*是什么意思?

请问这里使用的正则表达式引擎是什么? - JaredPar
Lua!http://www.lua.org/pil/20.1.html - doremi
1
@doremi:在阅读了文档之后,我发现Lua的正则表达式是一个相当强大的工具。正则表达式的含义可能会因为它是与gmatch还是match一起使用而发生改变。 - nhahtdh
你应该接受RBerteig的答案,因为他对Lua最相关,并且在解释正在发生的事情方面更详细。 - greatwolf
Lua模式看起来与正则表达式非常相似,但并不相同 - RBerteig
4个回答

22
"

(^?) 只是在查找字面上的字符^。当正则表达式模式中使用^作为第一个字符或分组匹配[]中的第一个字符时,^字符才具有特殊含义。在这两个位置之外使用^时,它被解释为查找输入字符串中的^字符。

注意:是否将^在第一个和分组位置之外解释为字面含义取决于正则表达式引擎。我不熟悉LUA,无法确定其具体情况。

"

3
关于 (^?)* 的无意义,我不作评论。它可以匹配 0 或 1 个字符,只匹配 ^ 这个字符,多次匹配 0 到多次 - 这与 (^*) 可能相同,除非在使用多个组。 - AD7six
这可能是一个糟糕的正则表达式,因为它是由别人提供给我的。这也是我试图理解它的原因之一。 - doremi
@JaredPar:你的例子非常令人困惑。.NET是一个相当糟糕的例子,因为它在你所列举的每个情况中都有特殊含义。Lua也许把“^”视为字面字符,但我需要再次确认。 - nhahtdh
@nhahtdh 我的模式中有5个^出现,但只有3个具有特殊含义。 - JaredPar
@JaredPar:它们都有特殊的含义。我已经在regexhero (.NET测试器)上检查过了。我认为你应该使用Match而不是IsMatch来详细检查实际匹配的内容:http://ideone.com/T6Jyxu - nhahtdh
显示剩余4条评论

7
Lua没有传统的正则表达式语言,它有自己的Lua模式。虽然它们看起来很像正则表达式,但Lua模式是一种独特的语言,具有更简单的规则,最重要的是缺少分组和选择功能。
将其解释为Lua模式,这个示例会让长期使用正则表达式的用户感到惊讶,因为很多细节都不同。
Lua模式《Programming in Lua》中有描述,乍一看与传统正则表达式相似,容易引起混淆。最大的区别可能是缺少替换操作符|,括号仅用于标记捕获,量词(?-+*)仅适用于字符或字符类,并且%是转义字符而不是\。一个很明显的线索是,该示例可能没有考虑Lua中的模式引用字符%应用于模式字符串中的任何(或理想情况下,所有)非字母数字字符,并且可疑使用\?的方法闻起来像传统的正则表达式,以匹配单个文字?
简单地回答这个问题: (^?)* 不是一个推荐的形式,它会匹配 ^**,捕获插入符的存在或缺失。如果这是预期的效果,那么我会写成 (%^?)%* 来使其更清晰。
为了看到这种情况,让我们将给定的模式作为Lua模式进行分析。整个模式是:
^(^?)*\?(.*)$

如果将其交给 string.match(),则会按以下方式解释:

^ 将匹配锚定到字符串的开头。

( 标记第一个捕获的开始。

^ 不在模式或字符类的开头,因此它匹配字面上的 ^ 字符。为了清晰起见,可能应该写成 %^

? 匹配前一个字符的零次或一次。

) 标记第一个捕获的结束。

* 不在可量化的内容之后,因此它匹配字面上的 * 字符。为了清晰起见,可能应该写成 %*

在模式中,\匹配它本身,它不是模式语言中的转义字符。但是,在Lua短字符串文字中,它是一个转义字符,使得以下字符对于字符串文字解析器来说不是特殊的,这种情况下是无意义的,因为后面跟随的?在任何情况下都不是它所特别关注的。因此,如果将模式括在双引号或单引号中,则\将被字符串解析吸收。如果写成长字符串(如[[^(^?)*\?(.*)$]]),反斜杠将幸存下来,出现在模式中。 ?匹配前一个字符的零次或一次。 (标记第二个捕获的开始。 .匹配任何字符,实际上是类[\000-\255]的同义词(请记住,在Lua中,数字转义使用十进制而不是C中的八进制)。 *匹配前一个字符的零次或多次,贪婪地。 )标记第二个捕获的结束。 $将模式锚定到字符串的末尾。
所以它匹配并捕获字符串开头的可选的^,接着是*,然后是一个未被捕获的可选的\,并捕获剩下的整个字符串。string.match成功时会返回两个字符串(其中一个或两个都可能为空),失败时返回nil编辑:我已经修正了一些错别字,并更正了我的回答中由Egor在评论中指出的错误。我忘记了在模式中,特殊符号失去了其特殊性,当它不能应用时。这使得第一个星号匹配了一个文字星号,而不是错误。这个级联影响到了大部分的回答。
请注意,如果你真的想在Lua中使用真正的正则表达式,有一些可用的库可以提供它。话虽如此,内置的模式语言非常强大。如果它不足够,那么你最好采用完整的解析器,并使用LPeg,它可以做任何正则表达式可以做的事情,甚至还带有一个模块,提供了一个完整的正则表达式语法,可以将其转换为LPeg语法以执行。

实际上,第一个 * 不是错误,它只是没有魔力。例如,assert(string.match("^*", "^(^?)*")) - Egor Skriptunoff
@EgorSkriptunoff 我认为你是对的。效果基本相同,但模式不匹配正则表达式用户认为它应该匹配的内容。 - RBerteig

2
在这种情况下,(^?)是指前面的字符串"^",意思是字面上的字符“^”,就像Jared所说的那样。请查看regexlib以获取更多信息。
满足您所有正则表达式需求的网站:http://regexlib.com/CheatSheet.aspx

1
我认为创建这个表达式的人的意图是匹配问号之前的任意数量的^,但只想捕获第一个^的实例。然而,根据其他人的说法,它可能不是引擎中的有效表达式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接