我有以下示例文本
[Item 1](./path/notes.md)
[Item 2](./path)
[Item 3](./path/notes.md)
[Item 4](./path)
当我应用以下正则表达式 \[(.*)\].*(?!notes\.md).*\)
时,我希望在打印第一个捕获时得到以下输出组
Item 2
Item 4
但我最终得到的是
Item 1
Item 2
Item 3
Item 4
在我看来,负前瞻部分 (?!notes\.md)
由于某种原因被忽略了,所以正则表达式匹配了整个字符串。
真正让我困惑的是,积极的前瞻性工作如我所料。例如,使用 \[(.*)\].*(?=notes\.md).*\)
在打印第一个捕获组时返回以下内容
Item 1
Item 3
这是有道理的,所以我真的很困惑为什么负先行不能正常工作。
最佳答案
让我们来看看在第 1 项上匹配您的模式时会发生什么:
\[(.*)\]
匹配[Item 1]
.*
匹配(./path/notes.md
- 剩下的字符串现在是
)
(?!notes\.md)
检查剩余字符串是否与模式notes\.md
匹配。它没有,所以比赛继续。\)
匹配)
,匹配成功。
如果您更改它,使前瞻之前的 .*
位于前瞻内部 (\[(.*)\](?!.*notes\.md)。 *\)
),它现在将按如下方式工作:
\[(.*)\]
匹配[Item 1]
- 剩下的字符串现在是
(./path/notes.md)
(?!.*notes\.md)
检查剩余字符串是否与模式.*notes\.md
匹配,匹配失败(更准确地说,正则表达式引擎会在放弃匹配之前尝试回溯,但没有其他方法可以匹配\[(.*)\]
',所以匹配仍然失败) .
因此,随着该更改,它将拒绝 notes.md
出现在 )
之前的所有字符串。如果您希望它只拒绝 notes.md
直接出现在 )
之前的实例,您可以使用 loookbehind(没有 .*
)或将 \)
添加到 lookahead。
关于正则表达式负先行被忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66947059/