Есть ли способ сделать отрицательный lookahead в Vim regex?

в Vim есть способ поиска строк, которые соответствуют say abc но также не содержат xyz позже на линии? Таким образом, следующие строки будут совпадать:

The abc is the best
The first three letters are abc

и не соответствует:

The abc is the best but xyz is cheaper
The first three letters are abc and the last are xyz

Я знаю о синтаксисе примерно следующим образом:

/abc(xyz)@!

но это только избегает сопоставления abcxyz и нет, если есть что-то между ними, например abc-xyz. Используя

/abc.*(xyz)@!

также не работает, потому что там есть много позиций позже в строке, где xyz не соответствует.

(я должен отметить, что в командной строке я бы сделал что-то вроде grep abc <infile | grep -v xyz но я хотел бы сделать это в интерактивном режиме в Vim.)

4 ответов


ваша попытка была довольно близка; вам нужно тянуть .* это позволяет произвольное расстояние между совпадением и утвержденным позже несоответствием в негативный взгляд вперед:

/abc\(.*xyz\)\@!

Я думаю, это работает, потому что не-матч предпринимается для всех возможных матчей .*, и только когда все ветви исчерпаны, это \@! объявлен выполнены.


это работает для меня /abc\(.*xyz\)\@!


хотя ваш вопрос о lookahead, я нашел его во время поиска lookbehind. Таким образом, я публикую решение lookbehind, чтобы другие могли его найти.

Если вы ищите pattern2 не предшествует pattern1, то есть отрицательный lookbehind, искать:

\(pattern1\)\@<!pattern2

думаю, я бы написал это как /abc\(\(xyz\)\@!.\)*$

Я не уверен, что это быстрее, чем другие предложения (я думаю, что это может быть, так как он проверяет каждую позицию только один раз), но это имеет концептуальный смысл как:

"abc, за которым следует все, что не является xyz, любое количество раз до конца строки"

мне это нравится больше, чем" abc, за которым следует что-либо, за чем не следует xyz", как в других упомянутых шаблонах.