否定前瞻正则表达式

时间:2011-07-27 22:16:18

标签: javascript regex regex-lookarounds

我希望匹配以“.htm”结尾的所有字符串,除非它以“foo.htm”结尾。我对正则表达式一般都很体面,但负面的前瞻让我难过。为什么这不起作用?

/(?!foo)\.htm$/i.test("/foo.htm");  // returns true. I want false.

我应该使用什么?我想我需要一个“负面看背后”表达式(如果JavaScript支持这样的东西,我知道它没有)。

7 个答案:

答案 0 :(得分:91)

问题非常简单。这样就可以了:

/^(?!.*foo\.htm$).*\.htm$/i

答案 1 :(得分:18)

你所描述的(你的意图)是负面的后视,而Javascript不支持后视。

向前看从它们放置的角色向前看 - 你已经将它放在.之前。所以,你所拥有的实际上是说“只要从那个位置开始的前三个字符(.htm)不是.ht”,那么任何以foo结尾的东西都是真的。

通常,负面观察的替代方法是匹配超出您需要的范围,并仅提取您实际需要的部分。这很hacky,根据你的确切情况,你可能会想出其他的东西,但是这样的话:

// Checks that the last 3 characters before the dot are not foo:
/(?!foo).{3}\.htm$/i.test("/foo.htm"); // returns false 

答案 2 :(得分:2)

如上所述,JavaScript不支持负面的后置断言。

但你可以使用workaroud:

/(foo)?\.htm$/i.test("/foo.htm") && RegExp.$1 != "foo";

这将匹配以.htm结尾的所有内容,但如果匹配"foo",它会将RegExp.$1存储到foo.htm,因此您可以单独处理它。

答案 3 :(得分:2)

与Renesis一样,JavaScript中不支持“lookbehind”,因此可能只使用两个正则表达式组合:

!/foo\.htm$/i.test(teststring) && /\.htm$/i.test(teststring)

答案 4 :(得分:1)

String.prototype.endsWith ES6



console.log( /* !(not)endsWith */

    !"foo.html".endsWith("foo.htm"), // true
  !"barfoo.htm".endsWith("foo.htm"), // false (here you go)
     !"foo.htm".endsWith("foo.htm"), // false (here you go)
   !"test.html".endsWith("foo.htm"), // true
    !"test.htm".endsWith("foo.htm")  // true

);




答案 5 :(得分:1)

这个答案可能比必要的时间晚了一点,但是我将其留在这里,以防万一有人遇到同样的问题(问这个问题后7年零6个月)。

ECM2018标准中现在包含了lookbehinds,至少在最新版本的Chrome中受支持。但是,无论是否使用它们,您都可以解决难题。

前瞻性为负的解决方案:

let testString = `html.htm app.htm foo.tm foo.htm bar.js 1to3.htm _.js _.htm`;

testString.match(/\b(?!foo)[\w-.]+\.htm\b/gi);
> (4) ["html.htm", "app.htm", "1to3.htm", "_.htm"]

后向否定的解决方案:

testString.match(/\b[\w-.]+(?<!foo)\.htm\b/gi);
> (4) ["html.htm", "app.htm", "1to3.htm", "_.htm"]

(技术上)积极向前的解决方案:

testString.match(/\b(?=[^f])[\w-.]+\.htm\b/gi);
> (4) ["html.htm", "app.htm", "1to3.htm", "_.htm"]

所有这些RegExp以不同的方式告诉JS引擎相同的东西,它们传递给JS引擎的消息如下所示。

请在此字符串中找到以下所有字符序列:

  • 与其他文本(例如单词)分开;
  • 由一个或多个英文字母,下划线, 连字符,点或数字;
  • 以“ .htm”结尾;
  • 除此之外,“。htm”之前的序列部分可以是任何内容 但是“ foo”。

答案 6 :(得分:0)

你可以用类似的东西模仿负面的背后隐藏 /(.|..|.*[^f]..|.*f[^o].|.*fo[^o])\.htm$/,但程序化方法会更好。