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

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

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

Ответы [ 6 ]

24 голосов
/ 07 февраля 2010

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

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

Из этой ситуации можно выйти тремя путями:

  1. совпадение (not|this) и исключение любых совпадений с помощью среды, в которой вы находитесь (отрицание результатов совпадения)
  2. использовать отрицательный прогноз, если это поддерживается вашим механизмом регулярных выражений и выполнимо в ситуации
  3. переписать выражение, чтобы оно могло соответствовать : см. аналогичный вопрос, который я задавал ранее
16 голосов
/ 07 февраля 2010

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

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

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

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

13 голосов
/ 22 августа 2011

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

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

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

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

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

9 голосов
/ 30 марта 2013

Звучит так, будто вы пытаетесь смотреть в будущее негативно. то есть вы пытаетесь прекратить сопоставление, когда достигнете какого-либо разделителя.

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

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

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

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

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

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

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

См. Руководство по emacs regex: http://www.gnu.org/software/emacs/manual/html_node/emacs/Regexps.html

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

6 голосов
/ 08 февраля 2010

Попробуйте M-x flush-lines.

2 голосов
/ 04 августа 2015

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

;; 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...