Negative lookahead Regular Expression

2019-01-06 12:02发布

I want to match all strings ending in ".htm" unless it ends in "foo.htm". I'm generally decent with regular expressions, but negative lookaheads have me stumped. Why doesn't this work?

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

What should I be using instead? I think I need a "negative lookbehind" expression (if JavaScript supported such a thing, which I know it doesn't).

6条回答
对你真心纯属浪费
2楼-- · 2019-01-06 12:12

The problem is pretty simple really. This will do it:

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

查看更多
放我归山
3楼-- · 2019-01-06 12:19

You could emulate the negative lookbehind with something like /(.|..|.*[^f]..|.*f[^o].|.*fo[^o])\.htm$/, but a programmatic approach would be better.

查看更多
甜甜的少女心
4楼-- · 2019-01-06 12:20

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楼-- · 2019-01-06 12:22

What you are describing (your intention) is a negative look-behind, and Javascript has no support for look-behinds.

Look-aheads look forward from the character at which they are placed — and you've placed it before the .. So, what you've got is actually saying "anything ending in .htm as long as the first three characters starting at that position (.ht) are not foo" which is always true.

Usually, the substitute for negative look-behinds is to match more than you need, and extract only the part you actually do need. This is hacky, and depending on your precise situation you can probably come up with something else, but something like this:

// Checks that the last 3 characters before the dot are not foo:
/(?!foo).{3}\.htm$/i.test("/foo.htm"); // returns false 
查看更多
戒情不戒烟
6楼-- · 2019-01-06 12:25

As mentioned JavaScript does not support negative look-behind assertions.

But you could use a workaroud:

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

This will match everything that ends with .htm but it will store "foo" into RegExp.$1 if it matches foo.htm, so you can handle it separately.

查看更多
叼着烟拽天下
7楼-- · 2019-01-06 12:28

Like Renesis mentioned, "lookbehind" is not supported in JavaScript, so maybe just use two regexps in combination:

!/foo\.htm$/i.test(teststring) && /\.htm$/i.test(teststring)
查看更多
登录 后发表回答