好吧,非贪婪匹配正在工作 - 它获得满足正则表达式的最短字符串。您必须记住的是,正则表达式是一个从左到右的过程。所以它匹配第一个 Q,然后得到最短的字符数,然后是 XYZ。如果您希望它不超过任何 Q,则必须使用否定字符类:
Q[^Q]*?XYZ
[^Q] 匹配任何不是 Q 的字符。请注意,这仅适用于单个字符。如果您的开头分隔符是多个字符,则必须以不同的方式进行。为什么?好吧,取分隔符“PQR”,字符串是
foo PQR bar XYZ
如果您尝试使用之前的正则表达式,但您将字符类扩展为:
PQR[^PQR]*?XYZ
那么你会得到
'PQR bar XYZ'
如你所料。但是如果你的字符串是
foo PQR Party Time! XYZ
你不会得到任何匹配。这是因为 [] 描述了一个“字符类”——它只匹配一个字符。使用这些类,您可以匹配一系列字符,只需列出它们。
th[ae]n
将匹配“than”和“then”,但不匹配“thin”。在开头放置一个克拉 ('^') 会否定类 - 意思是“匹配除这些字符之外的任何内容” - 所以通过将我们的单字符分隔符转换为 [^PQR],而不是说“不是 'PQR'”,你'重新说“不是'P','Q'或'R'”。如果你愿意,你仍然可以使用它,但前提是你 100% 确定你的分隔符中的字符只会在你的分隔符中。如果是这种情况,使用贪婪匹配会更快,并且只否定定界符的第一个字符。正则表达式将是:
PQR[^P]*XYZ
但是,如果你不能保证,那么匹配:
PQR(?:.(?!PQR))*?XYZ
正则表达式不直接支持负字符串匹配(因为当您考虑它时无法定义),因此您必须使用负前瞻。
(?!PQR)
就是这样一个前瞻。它的意思是“断言接下来的几个字符不是这个内部正则表达式”,不匹配任何字符,所以
.(?!PQR)
匹配任何没有后跟 PQR 的字符。把它打包成一个组,这样你就可以懒洋洋地重复它,
(.(?!PQR))*?
并且您匹配“不包含我的分隔符的字符串”。我唯一做的就是添加一个 ?: 使其成为非捕获组。
(?:.(?!PQR))*?
根据您用于解析正则表达式的语言,它可能会尝试单独传回每个匹配的组(对于查找和替换很有用)。这使它无法这样做。
快乐的正则表达式!