Javascript 为什么((a(-b))(?!Z))与“中的a”匹配;“a-bZ”吗;?

Javascript 为什么((a(-b))(?!Z))与“中的a”匹配;“a-bZ”吗;?,javascript,regex,Javascript,Regex,我想写一个匹配的正则表达式 a a-b 但前提是这些序列后面没有Z ((a(-b)?)(?!Z)) a matches a ok a-b matches a-b ok aZ empty ok a-bZ matches a NOT OK 虽然(a(-b)周围有一群人,为什么“a-bZ”与第一个a匹配? 我怎样才能纠正它 在javascript RegExp中需要这个,但是这不重要。在a-bZ中尝试了它,因

我想写一个匹配的正则表达式

a
a-b
但前提是这些序列后面没有Z

((a(-b)?)(?!Z))

a       matches a       ok
a-b     matches a-b     ok
aZ      empty           ok
a-bZ    matches a       NOT OK
虽然(a(-b)周围有一群人,为什么“a-bZ”与第一个a匹配? 我怎样才能纠正它


在javascript RegExp中需要这个,但是这不重要。在
a-bZ
中尝试了它,因为
(-b)?
被忽略,并且
(?!Z)
-
符号匹配

因为
(-b)
是可选的,所以
((a)(?!Z))
格式的每个字符串也会得到匹配。 您可以匹配
(a(?!Z))|(a-b(?!Z))

但是,这将匹配
a-bZ
(因为a后面跟一个非Z字符)

如果要查找字符串的所有实例,例如,
a-c
不匹配(即使
-
是非Z字符),可以执行以下操作:

(a(?![-Z]))|(a-b(?!Z))

如果指定开始和结束锚点,则上述正则表达式((a(-b))(?!Z))将与字符串
a-bZ
不匹配,请参见演示。由于未指定锚定,并且
(-b)
是可选的,因此正则表达式引擎首先尝试在任何位置匹配
a-b
,然后在看到以下
Z
字母时放弃匹配。现在,由于可选的
-b
,正则表达式引擎会回溯以获得匹配。现在它在
a
上,字母
a
后面不会紧跟着
Z
,因此引擎现在匹配字母
a

您可以使用原子分组使正则表达式工作。不幸的是,JavaScript正则表达式引擎不支持此功能

但是有一个技巧可以使用向前看和向后引用()来模拟其效果:

因此,在您的
a-b
或只是
a
情况下,这将变成:

(?=(a-b|a))\1(?!Z)
请注意,需要在组中首先提到较长的子模式
a-b
,否则它将不起作用


关键机制是,前瞻查找最早、最长的子匹配,而后退引用防止引擎中的任何回溯并移动字符串中的位置,因此可以执行以下测试
(?!Z)

由于b是可选的,所以
(a(-b)
匹配为
a
,然后它后面是
-
,它不是Z,所以负前瞻性不匹配。这很有道理。你是对的,我把前瞻和消费混为一谈,thx.?>在JS中不受支持那么呢?thx@raina77ow,是的,这很有效,缺点是我对a和b的定义很长,所以重复b有点痛。但是看起来没有出路了。Thx也指向regex101,真的很酷。?!不使用匹配中的字符,我认为这一点值得一提。实际上,这在模式中没有任何重复-
/(?=(a(-b))\1(?!Z)/
(),出于同样的原因-先尝试“前瞻”中最长的模式。对于我来说,这个答案如何不被OP接受才是真正的难题。)来得太晚了。从我的经验来看:这样的正则表达式线程通常在第一个可行的答案时死亡,OP很少考虑或认可所提供的备选方案。@raina77ow:最长的模式是首先尝试的,因为
,比如
a-b | a
的顺序意味着试验的顺序。当你让它变得懒惰时,你就会理解我的观点:
/(?=(a(-b)?)\1(?!Z)/
(?=(a-b|a))\1(?!Z)