Как мне написать регулярное выражение, которое исключает, а не сопоставляет, например, не (эта|строка)?

Я в тупике, пытаясь создать регулярное выражение Emacs, исключающее группы. [^] исключает отдельные символы в наборе, но я хочу исключить определенные последовательности символов: что-то вроде [^(not|this)], чтобы строки, содержащие "не" или "это", не совпадали.

В принципе, я мог бы написать ([^n][^o][^t]|[^...]), но есть ли другой способ, более чистый?


person Anycorn    schedule 07.02.2010    source источник
comment
@Гамбо. ты прав, спасибо   -  person Anycorn    schedule 07.02.2010
comment
Щелкните тег regex-negation, чтобы просмотреть похожие вопросы.   -  person finnw    schedule 09.02.2010
comment
Существует патч (не принятый) для предварительных утверждений, который делает это возможным: debbugs.gnu. org/db/53/5393.html   -  person Matt Curtis    schedule 26.04.2019


Ответы (8)


Прежде всего: [^n][^o][^t] не является решением. Это также исключит такие слова, как nil ([^n] не соответствует), bob ([^o] не соответствует) или cat ([^t] не соответствует).

Но можно создать регулярное выражение с базовым синтаксисом, которое соответствует строкам, не содержащим ни not, ни this:

^([^nt]|n($|[^o]|o($|[^t]))|t($|[^h]|h($|[^i]|i($|[^s]))))*$

Шаблон этого регулярного выражения состоит в том, чтобы разрешить любой символ, который не является первым символом слов или только префиксами слов, но не целыми словами.

person Gumbo    schedule 07.02.2010
comment
+1, и если бы у меня когда-нибудь возникло искушение переключиться на Emacs, это было бы достаточной причиной не делать этого. Как можно жить без прогнозов? :П - person Alan Moore; 07.02.2010
comment
До сих пор мне очень нравился Emacs, это мое первое... - person biocyberman; 03.08.2015

Это не просто возможно. Регулярные выражения предназначены для сопоставления вещей, и это все, на что они способны.

Прежде всего: [^] не обозначает «группу исключений», он обозначает отрицательный класс символов. Классы символов не поддерживают группировку в любой форме. Они поддерживают одиночные символы (и, для удобства, диапазоны символов). Ваша попытка [^(not|this)] на 100 % эквивалентна [^)(|hinots] в том, что касается механизма регулярных выражений.

Из этой ситуации могут выйти три пути:

  1. сопоставить (not|this) и исключить любые совпадения с помощью среды, в которой вы находитесь (отменить результаты сопоставления)
  2. используйте отрицательный прогноз, если он поддерживается вашим механизмом регулярных выражений и возможен в данной ситуации.
  3. перепишите выражение, чтобы оно могло соответствовать: см. похожий вопрос, который я задавал ранее
person Tomalak    schedule 07.02.2010
comment
Интересно, почему за этот ответ так мало голосов, это самый ясный ответ здесь! - person Hi-Angel; 04.08.2014
comment
@Yagamy Потому что он более или менее говорит, что не работает, хотя явно есть способ заставить его работать (хотя и непрактичный, это скорее последнее средство). - person Tomalak; 05.08.2014
comment
Я не вижу здесь утверждения «Не работает», даже наоборот: вы показали три способа, которые могут решить проблему, а третий точно такой же, как и принятый ответ. - person Hi-Angel; 05.08.2014
comment
@Yagamy Верно, но магический трюк впечатляет гораздо больше, чем предостерегающий ответ. Это не умаляет принятого ответа, делать это таким образом - единственный вариант иногда, но в большинстве случаев это чертовски громоздко. Я упомянул этот вариант последним по причине. Думаю, людям больше нравятся ответы с вау-эффектом. :) - person Tomalak; 05.08.2014
comment
это действительно отличный ответ, поскольку он помогает понять проблему таким образом, чтобы ее было легче решить. в emacs попробуйте M+X keep-lines удалить строки, которые не соответствуют тому, что вы хотите. - person RubyTuesdayDONO; 17.06.2015

Трудно поверить, что принятый ответ (от Гамбо) действительно был принят! Если только оно не было принято, поскольку в нем указывалось, что вы не можете делать то, что хотите. Если у вас нет функции, которая генерирует такие регулярные выражения (как показывает Gumbo), их составление будет настоящей головной болью.

Каков реальный вариант использования - что вы действительно пытаетесь сделать?

Как указал Томалак, (а) это не то, что делают регулярные выражения; (b) см. другой пост, на который он ссылается, для хорошего объяснения, включая то, что делать с вашей проблемой.

Ответ заключается в том, чтобы использовать регулярное выражение для соответствия тому, что вам не нужно, а затем вычесть это из исходного домена. IOW, не пытайтесь заставить регулярное выражение выполнять исключение (это невозможно); выполните исключение after, используя регулярное выражение, чтобы соответствовать тому, что вы хотите исключить.

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

person Drew    schedule 21.08.2011

Похоже, вы пытаетесь сделать отрицательный прогноз. то есть вы пытаетесь прекратить сопоставление, как только достигнете некоторого разделителя.

Emacs не поддерживает просмотр вперед напрямую, но поддерживает нежадную версию *, + и ? операторы (*?, +?, ??), которые в большинстве случаев можно использовать с той же целью.

Так, например, чтобы соответствовать телу этой функции javascript:

bar = function (args) {
    if (blah) {
        foo();
    }
};

Вы можете использовать это регулярное выражение emacs:

function ([^)]+) {[[:ascii:]]+?};

Здесь мы останавливаемся, когда находим последовательность из двух элементов «};». [[:ascii:]] используется вместо "." оператор, потому что он работает с несколькими строками.

Это немного отличается от отрицательного просмотра вперед, потому что }; сама последовательность, с которой она совпала, однако, если ваша цель состоит в том, чтобы извлечь все до этого момента, вы просто используете группу захвата \( и \).

См. руководство по регулярным выражениям emacs: http://www.gnu.org/software/emacs/manual/html_node/emacs/Regexps.html

В качестве примечания: если вы пишете какое-либо регулярное выражение emacs, обязательно вызовите M-x re-builder, который вызовет небольшую IDE для написания вашего регулярного выражения для текущего буфера.

person catphive    schedule 30.03.2013

Попробуйте M-x флеш-линии.

person offby1    schedule 07.02.2010

В случае использования сопоставления строки для логического теста я делаю следующее:

;; Code to match string ends with '-region' but excludes those that has 'mouse'.
M-x ielm RET
*** Welcome to IELM ***  Type (describe-mode) for help.
ELISP> (setq str1 "mouse-drag-region" str2 "mou-drag-region" str3 "mou-region-drag")
"mou-region-drag"
ELISP> (and (string-match-p "-region$" str1) (not (string-match-p "mouse" str1)))
nil
ELISP> (and (string-match-p "-region$" str2) (not (string-match-p "mouse" str2))) 
t
ELISP> (and (string-match-p "-region$" str3) (not (string-match-p "mouse" str3)))
nil

Я использую этот подход, чтобы избежать ошибки функции, которую я обсуждал Здесь:

person biocyberman    schedule 03.08.2015

Если вы пытаетесь использовать регулярное выражение для поиска или замены текста в буфере, вы можете использовать https://github.com/benma/visual-regexp-steroids.el/

Visual regexp steroids позволяет вам заменять, искать и т. д. с помощью python regex. Регулярное выражение Python поддерживает отрицательный взгляд вперед и отрицательный взгляд назад.

person KhaflaniW    schedule 11.05.2020
comment
Добро пожаловать в stackoverflow.com. Пожалуйста, включите все ключевые детали в свой ответ. Как написано, ваш ответ будет иметь мало значения, если внешняя ссылка изменится. Дополнительные сведения см. в разделе Как ответить. - person Simon.S.A.; 11.05.2020

Моя проблема заключалась в том, как передать отрицательное регулярное выражение в delete-lines, решение состояло в том, чтобы передать регулярное выражение M-x keep-lines

person eweb    schedule 06.04.2021