JavaScript 中的负后视等效项

IT技术 javascript regex negative-lookbehind
2021-01-13 00:16:23

有没有办法在 JavaScript 正则表达式中实现负向后视我需要匹配一个不以特定字符集开头的字符串。

如果在字符串的开头找到匹配的部分,我似乎无法找到执行此操作的正则表达式而不会失败。否定的lookbehinds似乎是唯一的答案,但JavaScript没有。

这是我想要使用的正则表达式,但它没有:

(?<!([abcdefg]))m

所以它会匹配“jim”或“m”中的“m”,但不匹配“jam”

6个回答

自 2018 年以来,Lookbehind Assertions成为ECMAScript 语言规范的一部分

// positive lookbehind
(?<=...)
// negative lookbehind
(?<!...)

2018 年之前的回答

由于 Javascript 支持负前瞻,一种方法是:

  1. 反转输入字符串

  2. 与反向正则表达式匹配

  3. 反转并重新格式化匹配项


const reverse = s => s.split('').reverse().join('');

const test = (stringToTests, reversedRegexp) => stringToTests
  .map(reverse)
  .forEach((s,i) => {
    const match = reversedRegexp.test(s);
    console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
  });

示例 1:

按照@andrew-ensley 的问题:

test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)

输出:

jim true token: m
m true token: m
jam false token: Ø

示例 2:

遵循@neaumusic 评论(匹配max-height但不匹配line-height,标记为height):

test(['max-height', 'line-height'], /thgieh(?!(-enil))/)

输出:

max-height true token: height
line-height false token: Ø
你能举一个有效的例子吗,说我想匹配max-height但不匹配line-height,我只想要匹配height
2021-03-13 00:16:23
这种方法的问题在于,当您同时拥有前瞻和后视时它不起作用
2021-03-26 00:16:23
如果任务是替换前面没有某个符号的两个连续的相同符号(并且不超过 2 个),则它无济于事。''(?!\()将替换''(''test'''''''test另一端的撇号,从而离开(''test'NNNtest而不是(''testNNN'test
2021-04-07 00:16:23

后向断言得到了接受ECMAScript规范在2018年。

正向后视用法:

console.log(
  "$9.99  €8.47".match(/(?<=\$)\d+\.\d*/) // Matches "9.99"
);

负面回顾用法:

console.log(
  "$9.99  €8.47".match(/(?<!\$)\d+\.\d*/) // Matches "8.47"
);

平台支持:

假设您想查找所有int不以 开头的内容unsigned

支持负向后视:

(?<!unsigned )int

不支持负向后视:

((?!unsigned ).{9}|^.{0,8})int

基本上的想法是抓取 n 个前面的字符并排除带有否定前瞻的匹配,但也匹配没有前面 n 个字符的情况。(其中 n 是后视的长度)。

所以有问题的正则表达式:

(?<!([abcdefg]))m

会翻译成:

((?!([abcdefg])).|^)m

您可能需要使用捕获组来找到您感兴趣的字符串的确切位置,或者您想用其他东西替换特定部分。

杰出的!使用否定前瞻作为旧 JavaScript 的解决方法!
2021-03-13 00:16:23
这应该是正确答案。请参阅:"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]") 返回"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'" 它非常简单并且有效!
2021-03-16 00:16:23
你能帮我解决这个问题吗:/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g
2021-03-30 00:16:23

Mijoja 的策略适用于您的特定情况,但不适用于一般情况:

js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
   function($0,$1){ return $1?$0:"[match]";});
Fa[match] ball bi[match] balll [match]ama

这是一个示例,其中目标是匹配双 l 但如果它前面是“ba”,则不是。请注意单词“ballll”——真正的后视应该抑制前 2 个 l 但匹配第二对。但是通过匹配前 2 个 l 然后忽略该匹配作为误报,正则表达式引擎从该匹配末尾继续进行,并忽略误报中的任何字符。

啊,你说得对。然而,这比我以前更接近了。我可以接受这一点,直到出现更好的东西(比如 JavaScript 实际实现了后视)。
2021-04-03 00:16:23

newString = string.replace(/([abcdefg])?m/, function($0,$1){ return $1?$0:'m';});
这不会做任何事情:newString永远等于string为什么这么多赞?
2021-03-19 00:16:23
@MikeM:因为重点只是演示匹配技术。
2021-03-21 00:16:23
@MikeM:SO 的规则是,如果它按书面形式回答问题,则它是正确的。OP 没有指定用例
2021-03-22 00:16:23
这个概念是正确的,但是它不是很好地演示。尝试在JS控制台中运行这个... "Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1){ return $1 ? $0 : '[match]'; });它应该返回Ji[match] Jam Mo[match][match] [match]但也要注意,正如下面提到的 Jason,它可能会在某些边缘情况下失败。
2021-03-29 00:16:23
@漏洞。没有做任何事情的演示是一种奇怪的演示。答案似乎只是复制和粘贴,而对它的工作原理一无所知。因此,缺乏伴随的解释和未能证明任何东西都匹配。
2021-04-03 00:16:23