Подтвердить что ты не робот

Vim Regex: как искать A AND B NOT C

У меня есть много строк, содержащих имена президентов США Картера, Буша, Клинтона, Обамы. Некоторые из них содержат 1 из этих имен, некоторые 2, некоторые 3, некоторые из всех 4 (в любом порядке).

Я знаю, как искать Картера И Клинтона и Обаму →

:g/.*Carter\&.*Clinton\&.*Obama/p

Я знаю, как искать Картера И (Клинтон ИЛИ Буш) →

:g/.*Carter\&\(.*Clinton\|.*Bush\)/p

(Есть, безусловно, лучшие способы сделать это)

Но я не могу понять, как искать (и я рассматривал связанные вопросы), например, для Буша и Клинтона НЕ Картера и даже меньше того, как искать, например, для Буша и Клинтона НЕ (Carter OR Obama).

4b9b3361

Ответ 1

Чтобы представить NOT, используйте отрицательное утверждение \@!.

Например, "NOT Bush" будет:

^\(.*Bush\)\@!

или используя \v:

\v^(.*Bush)@!

Важно: обратите внимание на начало ^. Хотя это необязательно, если вы используете только положительные утверждения (одно совпадение так же хорошо, как и любое другое), требуется привязать отрицательные утверждения (иначе они все равно могут совпадать в конце строки).

Перевод "Буш И Клинтон И НЕ (Картер ИЛИ Обама)":

\v^(.*Bush)&(.*Clinton)&(.*Carter|.*Obama)@!

Добавление

Объяснить связь между \& и \@=:

One&Two&Three

является взаимозаменяемым с:

(One)@=(Two)@=Three

Единственное отличие состоит в том, что \& прямо отражает \| (что должно быть более очевидным и естественным), а \@= зеркала Perl (?=pattern).

Ответ 2

Если вы хотите использовать регулярные выражения в стиле Perl после vim, забудьте о \&: это особенность, характерная для vim, которая бесполезна, поскольку vim также имеет lookaheads, поэтому любой r1\&r2 можно переписать как \%(r1\)\@=r2. Но взгляды лучше, поскольку есть отрицательная версия, и они также доступны в большинстве движков регулярного выражения в стиле Perl. Ваш (Bush AND Clinton AND NOT (Carter OR Obama)) может быть выражен следующим образом:

g/^\%(.*\%(Carter\|Obama\)\)\@!\%(.*Bush\)\@=.*Clinton/

Или, с очень магии:

g/^\v%(.*%(Carter|Obama))@!%(.*Bush)@=.*Clinton/

См. :h /\@=

О внутренней логике: look-ahead - как ветки: для регулярного выражения (reg1)@=reg2, предполагая, что reg2 соответствует в позиции N (совпадение начинается с позиции N), механизм regex проверяет, совпадает ли reg1 эта позиция. Если это не так, тогда позиция отбрасывается, и двигатель regex пытается выполнить следующее возможное совпадение для reg2. То же самое для негативного внешнего вида, но с той разницей, что regex engine отбрасывает позицию, если соответствует reg1.


Пример:

Regex: (.b)@!a.

Строка: aba.

  • Найдено совпадение: a соответствует в позиции 0 (aba). Попытка сопоставить прогноз: . соответствует a (aba) и b соответствует b (aba), совпадениям с опережением, отбрасыванию позиции.
  • Позиция 1 (aba) не соответствует a.
  • Найдено совпадение: a соответствует позиции 2 (aba). Попытка сопоставить прогноз "вперед": . соответствует a (aba), но b не соответствует: никаких символов не осталось, поиск вперед не выполняется. Результат: регулярное выражение соответствует позиции 2.