在Javascript中,我有一个字符串
abcdef
,但无法理解这种奇怪的行为:
(?=abc)def
不匹配该字符串abc(?=def)
匹配该字符串
abcdef
,但无法理解这种奇怪的行为:
(?=abc)def
不匹配该字符串abc(?=def)
匹配该字符串(?=abc)
表示捕获零宽度,即在成功匹配后不会将输入字符串中的光标向前移动。这个构造简单地说是看一下接下来的三个字符是否是abc
,如果是,然后检查这些字符是否为def
。此时匹配失败。abcdef
和正则表达式abc(?=def)
。引擎首先匹配a
,然后将光标移到输入字符串中的下一个字符,并尝试匹配b
。因为光标位于输入字符串的b
上,所以匹配成功。然后,引擎在输入字符串内部移动光标,并尝试匹配c
。由于光标位于输入字符串的c
上,所以匹配成功,并且再次将输入字符串中的光标移动到下一个字符。现在,引擎遇到了(?=def)
。此时,引擎只是向前查看,以查看从光标所在位置开始的下一个三个字符是否实际上是def
,而不移动光标,发现它们是的,因此匹配成功。xyz
和正则表达式x(?=y)Z
。正则表达式引擎将光标放置在输入字符串的第一个字母上,并检查它是否为x
,发现它是,所以将光标移到输入字符串的下一个字符。现在它向前查看,以查看下一个字符是否为y
,发现确实是,但是引擎不会将输入文本光标向前移动,因此输入文本中的光标仍停留在y
上。接下来,引擎查看光标是否位于字母z
上,但由于输入文本中的光标仍然位于y
上,因此匹配失败。您可以在http://www.regular-expressions.info/lookaround.html上阅读更多关于正向和负向先行断言的内容。^
,结果将是相同的。 - Zaffy(?=...)
是一个向前查找,也就是测试字符串右侧的内容。注意,向前查找是一种零宽断言,不会消耗字符。在您的第一个示例中:(?=abc)
表示必须在abc
之后遇到def
。这就是模式失败的原因。
在您的第二个示例中,它在abc
之后找到了def
,然后匹配了字符串。
/(?=def)def/.test('abcdef')
匹配。 - Fabrício Matté
x(?=y)
当且仅当'x'后跟'y'时,匹配'x'。这称为先行断言。例如,
/Jack(?=Sprat)/
仅在其后跟'Sprat'时匹配'Jack'。/Jack(?=Sprat|Frost)/
仅在其后跟'Sprat'或'Frost'时匹配'Jack'。然而,'Sprat'和'Frost'都不是匹配结果的一部分。
因此,如果(?=y)
前面有另一个语句,即空字符串,在此情况下,仅当第一个语句后跟第二个语句时才会匹配。 如果没有前导语句,则表达式(?="abc")
将在前3个字符abc上匹配而不捕获它们,然后再次检查这些字符是否为def,这将失败。
根据您对我的评论的回复,我认为您想要的是一个正向后顾:
(?<=abc)def
编辑:
既然您正在使用JavaScript(抱歉,我只看了您的问题,没有看标签),为什么不只使用一个普通的捕获组,并将匹配项包含在替换模式中呢?
"abcdef".replace(/(abc)def/, "$1")
/g
替换时会跳过已替换的文本。例如,"a1a2a".replace(/(a)(\d)(a)/g, "$1b$2b$3"); 将得到 "ab1ba2a" 而不是 "ab1bab2ba"。 - Zaffy"a1a2a".replace(/(a)(\d)(?=a)/g, "$1b$2b") // => "ab1bab2ba"
- DaoWen
(?:abc)def
,它使用的是非捕获组而不是正向先行断言。 - DaoWen"abcdef".replace(/(?:abc)def/, "")
它会替换整个字符串。 - Zaffy