我有这个正则表达式:
^(^?)*\?(.*)$
如果我理解正确,这是它的功能分解:
- ^ - 从字符串开头开始匹配
- (^?)* - 我不知道,但它将其存储在$1中
- \? - 匹配问号
- (.*)$ - 匹配直到字符串结尾的任何内容
我有这个正则表达式:
^(^?)*\?(.*)$
(^?)
只是在查找字面上的字符^
。当正则表达式模式中使用^
作为第一个字符或分组匹配[]
中的第一个字符时,^
字符才具有特殊含义。在这两个位置之外使用^
时,它被解释为查找输入字符串中的^
字符。
注意:是否将^
在第一个和分组位置之外解释为字面含义取决于正则表达式引擎。我不熟悉LUA,无法确定其具体情况。
(^?)*
的无意义,我不作评论。它可以匹配 0 或 1 个字符,只匹配 ^
这个字符,多次匹配 0 到多次 - 这与 (^*)
可能相同,除非在使用多个组。 - AD7six^
出现,但只有3个具有特殊含义。 - JaredParMatch
而不是IsMatch
来详细检查实际匹配的内容:http://ideone.com/T6Jyxu - nhahtdh|
,括号仅用于标记捕获,量词(?
、-
、+
和*
)仅适用于字符或字符类,并且%
是转义字符而不是\
。一个很明显的线索是,该示例可能没有考虑Lua中的模式引用字符%
应用于模式字符串中的任何(或理想情况下,所有)非字母数字字符,并且可疑使用\?
的方法闻起来像传统的正则表达式,以匹配单个文字?
。(^?)*
不是一个推荐的形式,它会匹配 ^*
或 *
,捕获插入符的存在或缺失。如果这是预期的效果,那么我会写成 (%^?)%*
来使其更清晰。^(^?)*\?(.*)$
如果将其交给 string.match()
,则会按以下方式解释:
^
将匹配锚定到字符串的开头。
(
标记第一个捕获的开始。
^
不在模式或字符类的开头,因此它匹配字面上的 ^
字符。为了清晰起见,可能应该写成 %^
。
?
匹配前一个字符的零次或一次。
)
标记第一个捕获的结束。
*
不在可量化的内容之后,因此它匹配字面上的 *
字符。为了清晰起见,可能应该写成 %*
。
\
匹配它本身,它不是模式语言中的转义字符。但是,在Lua短字符串文字中,它是一个转义字符,使得以下字符对于字符串文字解析器来说不是特殊的,这种情况下是无意义的,因为后面跟随的?
在任何情况下都不是它所特别关注的。因此,如果将模式括在双引号或单引号中,则\
将被字符串解析吸收。如果写成长字符串(如[[^(^?)*\?(.*)$]]
),反斜杠将幸存下来,出现在模式中。
?
匹配前一个字符的零次或一次。
(
标记第二个捕获的开始。
.
匹配任何字符,实际上是类[\000-\255]
的同义词(请记住,在Lua中,数字转义使用十进制而不是C中的八进制)。
*
匹配前一个字符的零次或多次,贪婪地。
)
标记第二个捕获的结束。
$
将模式锚定到字符串的末尾。^
,接着是*
,然后是一个未被捕获的可选的\
,并捕获剩下的整个字符串。string.match
成功时会返回两个字符串(其中一个或两个都可能为空),失败时返回nil
。
编辑:我已经修正了一些错别字,并更正了我的回答中由Egor在评论中指出的错误。我忘记了在模式中,特殊符号失去了其特殊性,当它不能应用时。这使得第一个星号匹配了一个文字星号,而不是错误。这个级联影响到了大部分的回答。*
不是错误,它只是没有魔力。例如,assert(string.match("^*", "^(^?)*"))
。 - Egor Skriptunoff