负前瞻正则表达式

IT技术 javascript regex regex-lookarounds
2021-02-18 07:16:00

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

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

我应该用什么代替?我想我需要一个“否定背后”的表达(如果 JavaScript 支持这样的东西,我知道它不支持)。

6个回答

问题其实很简单。这将做到:

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

+1。不仅不需要lookbehind,如果它可用,它也不是最好的工具。
2021-04-25 07:16:00
你能解释一下发生了什么吗?我看到您有一个行首标记 (^) 但有两个行尾标记 ($)。这如何使负前瞻工作?
2021-05-07 07:16:00
这么有用的技术!
2021-05-09 07:16:00
@ericbowden 如果您仍然想知道:它匹配字符串的开头,然后与.*foo\.htm字符串的结尾不匹配因为前瞻没有被消耗,它外面的第二个 $ 实际上是匹配的那个。
2021-05-11 07:16:00

您所描述的(您的意图)是负面的后视,而 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 
+1 很好的解释。但是,/(?!foo).{3}\.htm$/i将无法匹配少于三个字符的名称,即a.htm. 这是一个可以全部获得的方法:/^(?!.*foo\.htm$).*\.htm$/i
2021-04-18 07:16:00
你给了我足够的钱让我自己走完剩下的路。这适用于我的所有测试用例:/(^.{0,2}|(?!foo).{3})\.htm$/i
2021-04-30 07:16:00

如前所述,JavaScript 不支持否定的后视断言。

但是你可以使用一种解决方法:

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

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

2021-05-07 07:16:00

就像 Renesis 提到的那样,JavaScript 不支持“lookbehind”,所以也许只需组合使用两个正则表达式:

!/foo\.htm$/i.test(teststring) && /\.htm$/i.test(teststring)
JavaScript 支持前瞻。
2021-04-24 07:16:00
thx :) 刚想起一年前,可能我的记忆力不太好
2021-05-15 07:16:00

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

);