Как превратить любое регулярное выражение в дополнение к самому себе без сложного ручного редактирования? - PullRequest
13 голосов
/ 20 октября 2010

Ниже приведены псевдо-примеры, не реальное регулярное выражение, но все еще пример того, что я имею в виду:


.* (anything)

-.* (NOT anything)

[A-Z] (Any letter A to Z, caps only)

-[A-Z] (NOT any letter A to Z, caps only)

РЕДАКТИРОВАТЬ: Изменен обратный в дополнение в вопросе. Вот где было сделано изменение: «превратить любое регулярное выражение в дополнение самого себя»

Ответы [ 6 ]

13 голосов
/ 20 октября 2010

Прежде всего, я полагаю, что вы имеете в виду дополнение регулярного выражения, а не обратное.Обратное регулярное выражение не имеет большого смысла;но если рассматривать ее как функцию, я полагаю, вы могли бы сказать, что обратная сторона сопоставителя - это генератор, который генерирует все совпадающие строки - или что-то в этом роде.С другой стороны, дополнение языка - это все эти строки , а не в исходном языке.

Далее, здесь необходимо рассмотреть два представления:

Принципиально

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

См. Статью в Википедии о Regular Languages ​​ в качестве отправной точки.

Практически

Типичный perl-совместимый синтаксис регулярных выражений, используемый в настоящее время в большинстве современных языков, не имеет оператора дополнения.Для регулярного выражения complete вы можете получить что-то похожее, используя оператор отрицательного просмотра: (?!X) будет точно соответствовать строке, а X - нет.Однако это плохая замена оператора дополнения, поскольку вы не сможете использовать его как часть большего регулярного выражения обычным способом;это регулярное выражение не "потребляет" входные данные, что означает, что он ведет себя по-разному в сочетании с другими операторами.

Например, если вы сопоставите числовые строки как [0-9]*, чтобы соответствовать всей строке, которую вы добавляете ^ и добавьте $, но чтобы использовать эту технику для поиска дополнения, вам нужно написать ^(?!^[0-9]*$).*$ - и обычная конкатенация такого отрицательного регулярного выражения, насколько я могу судить, не может быть отменена.

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

8 голосов
/ 20 октября 2010

Просто запустите регулярное выражение и логически инвертируйте вывод.Поэтому измените:

if(/foo/)

на:

if(!/foo/)

Классы символов можно инвертировать с помощью начального карата:

[AZ] -> [^ AZ]

У многих специальных символов тоже есть обратные, если вы опишите заглавную букву.

\s whitespace
\S non-whitespace
\w word character
\W non-word-character
\d digit
\D non-digit
6 голосов
/ 20 октября 2010

Несколько вариантов для рассмотрения:

Соответствует строке, которая состоит из определенного набора символов: ^[a-z]*$

Соответствует строке, которая состоит из всего, кроме aопределенный набор символов: ^[^a-z]*$

Обратите внимание, что есть некоторые комбинации клавиш:

  • \w: любой буквенно-цифровой символ (включая _),
  • \W: любой не алфавитно-цифровой символ;
  • \s: любой символ пробела,
  • \S: любой символ без пробела,
  • \d:любая цифра,
  • \D: любая не цифра.

Это может быть довольно сложно, например, если вы хотите ...

  • только не буквы: [\d_\W] или
  • только буквы: [^\d_\W] (т. е. «не цифра, не _ и не алфавитно-цифровой символ)

Соответствует строке, которая содержит подстроку: ^.*substring.*$

Соответствует строке, которая не содержит подстроку: ^(?:(?!substring).)*$

Обратите внимание, как мыдолжны проверить каждую позицию встрока для "отсутствия присутствия" подстроки.Вы также можете заменить любое регулярное выражение на substring, чтобы оно соответствовало строкам, которые содержат или не содержат определенного под-регулярного выражения.


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

Совпадение с любым, если вы не знаете, как установить эту опцию: [\s\S]*

Никогда ничего не соответствует (по какой-либо причине):

  • $^ (то есть соответствует концу строки перед началом строки),
  • \b\B (соответствует позиции, в которой одновременно находится граница слова, а не границы слова) или
  • (?!) (соответствует позиции, в которой невозможно сопоставить пустую строку).
4 голосов
/ 20 октября 2010

Используя отрицательный прогноз, вы сможете обрабатывать большинство основных случаев

/(?!(OriginalRegex)).*?/
3 голосов
/ 20 октября 2010

Ваш первый пример не имеет смысла, но для второго вы можете использовать отрицание символа класса:

[a-z] --> [^a-z]
1 голос
/ 20 октября 2010

Я пытаюсь понять определение обратного регулярного выражения.

match (input, Обычное_выражение) = {match1, match2, ..., matchN}

Как будет работать обратное?Должно ли это быть что-то вроде

match (input, inverse_regular_expression) = {imatch1, imatch2, ..., imatchN}

Если это так, какова связь междупервый набор результатов, а второй?Если нет, то что это?

...