负向先行断言中的字符串被部分捕获

4

我常用的正则表达式:

/(?!#REF!)([^!,]{1,99})!/g

我的测试字符串:

foo,#REF!,bar!,baz,qux!

目前它匹配 REF!,但期望的结果是仅匹配 bar!qux!。我使用了负向先行断言 (?!#REF!) 来防止这种情况,但 REF! 仍然被捕获,因为它与 [^!,]{1,99} 匹配。如何避免匹配 REF! - 是否使用负向先行断言是正确的方法?

1
请确保您从字符串或逗号的开头开始匹配,(?:^|,)(?!#REF!)([^!,]{1,99})!,您的值在第一组中。顺便说一句,您的模式中只有一个捕获组。 - Wiktor Stribiżew
是的,但它没有捕获它。就像我写的那样,你的值在第一组中。 - Wiktor Stribiżew
1
一种非正则表达式的方法也是可能的 在此 - Wiktor Stribiżew
@WiktorStribiżew:你的正则表达式实际上应该是(?:^|,)(?!#REF!)([^!,]{1,99}!),否则反向引用将不会考虑到最后一个!,因为它不会被捕获。 - Allan
@Allan 这里没有反向引用。 - Wiktor Stribiżew
显示剩余2条评论
2个回答

2

由于你的字符串是逗号分隔的项目列表,因此您可以使用逗号拆分字符串,删除所有空项目(如果有),仅获取以结尾的项目,然后从字符串末尾删除

var s = "foo,#REF!,bar!,baz,qux!";
console.log(s.split(',')
 .filter(Boolean)     // remove empty items
 .filter(function (x) {return x.charAt(x.length-1)==="!" && x!== "#REF!";} ) // ends with ! and not #REF!
  .map(function(y) {return y.substr(0, y.length-1)}) // remove !
);

如果由于某些原因您仍需要使用正则表达式,可以使用以下方法:
/(?:^|,)(?!#REF!)([^!,]{1,99})!/g

访问 Group 1 的值。在此查看正则表达式演示

注意:这里只有一个捕获组,因为(?!...)是一个特殊的正则表达式构造,是一个 前瞻。而(?:...)是一个非捕获组,与捕获组相比,其值不会存储在任何额外的内存缓冲区中。

详情

  • (?:^|,) - 起始位置要么是字符串的开头,要么就是,
  • (?!#REF!) - 当前位置之后不允许出现#REF!
  • ([^!,]{1,99}) - 捕获组1: 除了!,之外的1到99个字符
  • ! - 一个!字符

var s = "foo,#REF!,bar!,baz,qux!";
var rx = /(?:^|,)(?!#REF!)([^!,]{1,99})!/g, m, res=[];
while (m=rx.exec(s)) {
   res.push(m[1]);
}
console.log(res);


0

您可以使用以下正则表达式:

(?<=^|,)(?!#REF!)([^!,]{1,99})!

解释:

添加 (?<=^|,) 强制你的正则表达式匹配要么从行首开始,要么从前一个逗号开始。如果不添加它,REF! 也会被匹配。逗号 , 不会成为结果的一部分,因为它在回顾后面的子句中。

DEMO

如果您不能使用回顾,则可以选择像 WiktorStribizew 提出的解决方案。

(?:^|,)(?!#REF!)([^!,]{1,99}!)

通过引用第1个捕获组


3
请注意,JavaScript正则表达式中的向后查找功能是最近才开发出来的。例如,在目前存在的任何Firefox版本中都无法使用此功能。 - Ry-
@Ry︁:你说得完全正确,我已经相应地编辑了我的答案!感谢您的反馈。 - Allan
谢谢 - 我会选择Wiktor的,但还是点了赞。 - Robin Mackenzie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接