我希望匹配以“.htm”结尾的所有字符串,除非它以“foo.htm”结尾。我对正则表达式一般都很体面,但负面的前瞻让我难过。为什么这不起作用?
/(?!foo)\.htm$/i.test("/foo.htm"); // returns true. I want false.
我应该使用什么?我想我需要一个“负面看背后”表达式(如果JavaScript支持这样的东西,我知道它没有)。
答案 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引擎的消息如下所示。
请在此字符串中找到以下所有字符序列:
答案 6 :(得分:0)
你可以用类似的东西模仿负面的背后隐藏
/(.|..|.*[^f]..|.*f[^o].|.*fo[^o])\.htm$/
,但程序化方法会更好。