Отрицательный просмотр вперед регулярного выражения


Я хочу сопоставить все строки, заканчивающиеся на ".htm "если это не заканчивается" foo.htm". Я вообще приличный с регулярными выражениями, но отрицательные взгляды меня озадачили. Почему это не работает?

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

что я должен использовать вместо? Я думаю, что мне нужен "негативный взглядза" выражение (если JavaScript поддерживает такую вещь, которую я знаю, что это не так).

6 54

6 ответов:

проблема довольно проста на самом деле. Это будет делать это:

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

то, что вы описываете (ваше намерение) отрицательный посмотреть-за, и Javascript не поддерживает look-behinds.

посмотрите-aheads смотрят вперед от персонажа, на котором они размещены - и вы разместили его перед .. Итак, то, что у вас есть, на самом деле говорит: "все, что заканчивается .htm пока первые три символа, начиная с этой позиции (.ht) не foo", которое всегда истинно.

как правило, замена для отрицательного взгляда-behinds должен соответствовать больше, чем вам нужно, и извлекать только ту часть, которая вам действительно нужна. Это хаки, и в зависимости от вашей конкретной ситуации вы, вероятно, можете придумать что-то еще, но что-то вроде этого:

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

как уже упоминалось JavaScript не поддерживает отрицательные утверждения look-behind.

но вы могли бы использовать workaroud:

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

это будет соответствовать все, что заканчивается .htm а "foo" на RegExp. если он соответствует foo.htm, так что вы можете справиться с этим отдельно.

Как упоминалось в Renesis, "lookbehind" не поддерживается в JavaScript, поэтому, возможно, просто используйте два регулярных выражения в сочетании:

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

строку.прототип.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

);

вы можете эмулировать негативный взгляд с чем-то вроде /(.|..|.*[^f]..|.*f[^o].|.*fo[^o])\.htm$/, но программный подход был бы лучше.