Отрицание обратной ссылки в регулярных выражениях

если строка имеет этот предсказанный формат:

value = "hello and good morning"

Где " (кавычки) также могут быть ' (одинарными кавычками), а закрывающий символ (' или ") будет таким же, как и открывающий. Я хочу сопоставить строку между кавычками.

\bvalue\s*=\s*(["'])([^\1]*)\1

(два символа \ должны разрешать любые пробелы рядом со знаком =)

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

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

Это делает:

\bvalue\s*=\s*(['"])([^"']*)["']

но я хочу убедиться, что и открывающая, и закрывающая кавычка (двойная или одинарная) одинаковы.


РЕДАКТИРОВАТЬ
Основная цель заключалась в том, чтобы получить открывающий тег якоря, в атрибут класса которого включено определенное имя класса, и я хотел охватить редкий случай атрибут класса, включающий (') или (").

Следуя всем советам здесь, я использовал шаблон:

<\s*\ba\b[^<>]+\bclass\s*=\s*("|'|\\"|\\')(?:(?!\1).)*\s*classname\s*(?:(?!\1).)*\1[^>]*>

Значение:
Найдите знак открытия тега.
Разрешить любые пробелы.
Найдите слово а.
Разрешить любой незакрывающий тег.
Найти "класс (любые пробелы) = (любые пробелы)"
Получить открывающие кавычки, один из следующих: (" или ' или \" или \').
Из ответа Алана Мура: Разрешить любые символы, которые не являются открывающими кавычками.
найти имя класса
Разрешить любые символы, кроме открывающих кавычек.
Найдите закрывающую цитату, которая совпадает с открывающей.
Разрешить любые символы открывающего тега.
Найдите закрывающий тег char.


person Yuval A.    schedule 08.11.2011    source источник
comment
Можно ли экранировать кавычки? т.е. value = 'O\'Neill'   -  person Bart Kiers    schedule 08.11.2011


Ответы (6)


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

\bvalue\s*=\s*(["'])(?:(?!\1).)*\1

(?:(?!\1).)* потребляет по одному символу за раз, после просмотра вперед подтвердит, что символ не соответствует тому, что было сопоставлено группой захвата, (["'']). Класс символов, инвертированный или нет, может одновременно соответствовать только одному символу. Насколько известно движку регулярных выражений, \1 может представлять любое количество символов, и нет никакого способа убедить его, что \1 будет содержать только " или ' в этом случае. Таким образом, вы должны использовать более общее (и менее читаемое) решение.

person Alan Moore    schedule 08.11.2011
comment
Итак, эта часть: (?!\1) означает: сопоставьте все, что следует, но убедитесь, что это не то, что в \1 ? Это то, что мне было нужно, спасибо. - person Yuval A.; 09.11.2011
comment
Я вижу, что это работает правильно только внутри группы без захвата, как вы. Я только наполовину понимаю, почему он должен быть внутри группы без захвата... - person Yuval A.; 09.11.2011
comment
Отрицательный просмотр вперед, (?!\1), на самом деле ничего не соответствует, он просто утверждает, что невозможно найти соответствие \1 в текущей позиции. Это ., который фактически соответствует (т. е. потребляет) следующему символу. - person Alan Moore; 10.11.2011
comment
Что касается группы без захвата, то это была всего лишь политика; Я использовал его, потому что мне не нужно было необходимо использовать там группу захвата. Выложенное мной регулярное выражение должно работать в любом случае, хотя ((?!\1).)* было бы неоправданно неэффективным. Что еще более важно, группы нумеруются в соответствии с их положением в регулярном выражении, поэтому использование групп без захвата, когда это возможно, значительно упрощает отслеживание номеров групп захвата. - person Alan Moore; 10.11.2011
comment
Вы... должны использовать отрицательный прогноз (?) - person Code Jockey; 15.09.2017

Ты можешь использовать:

\bvalue\s*=\s*(['"])(.*?)\1

Посмотреть

person codaddict    schedule 08.11.2011
comment
@YuvalA: ты прав. У нас не может быть обратной ссылки в классе char. - person codaddict; 08.11.2011
comment
Я призываю вас удалить этот ответ - это один из тех неудачных случаев, когда кажется, что он должен работать и является самым простым решением, но на самом деле не работает на практике. - person Trey; 03.05.2020

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

Используя эти строки:

value = "hello and good morning"
value = 'hola y buenos dias'
value = 'how can I say "goodbye" so soon?'
value = 'why didn\'t you say "hello" to me this morning?'
value = "Goodbye! Please don't forget to write!"
value = 'Goodbye! Please don\'t forget to write!'

это выражение:

"((\\"|[^"])*)"|'((\\'|[^'])*)'

будет соответствовать этим строкам:

"hello and good morning"
'hola y buenos dias'
'how can I say "goodbye" so soon?'
'why didn\'t you say "hello" to me this morning?'
"Goodbye! Please don't forget to write!"
'Goodbye! Please don\'t forget to write!'

Это позволило бы либо «другой» тип цитаты, либо тот же тип цитаты, когда он экранирован одним предшествующим \. Содержимое строк в кавычках находится либо в группе 1, либо в группе 3. Вы можете выяснить, какой тип кавычек используется, получив первый (или последний) символ.

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

Пожалуйста, спросите, хотите ли вы пойти по этому маршруту и ​​вам нужна дополнительная помощь.

person Code Jockey    schedule 08.11.2011
comment
Мне любопытно, откуда взялся отрицательный голос - кто-нибудь хочет сказать мне, что мне не хватает? Я спокойно отношусь ко всем, кто предпочитает более эффектные, менее регулярные функции более современных разновидностей регулярных выражений простому чередованию, но... мой подход... не работает... для какого-то варианта использования?? - person Code Jockey; 15.09.2017
comment
Я не могу говорить за даунвотера, но: 'this shouldn\'t match - person Coleoid; 05.02.2019


Пример замены:

"markdown *text*"

to:

"markdown <em>text</em>"

PHP-код №1 для символов * и _ (жадный режим):

preg_replace('%'.'([*_])'.'(?<phrase>.+?)'.'\\1'.'%sS', '<em>$2<em>', $text);

Код PHP #2 для символов * и _ (отрицание в обратной ссылке):

preg_replace('%'.'([*_])'.'(?<phrase>(?:(?!\\1).){1,})'.'\\1'.'%sS', '<em>$2<em>', $text);

PHP-код #3 для одного символа * (отрицание в классах символов):

preg_replace('%'.'([*])'.'(?<phrase>[^*]{1,})'.'[*]'.'%sS', '<em>$2<em>', $text);

Случай №1 (жадный режим) быстрее, чем Случай №2 (отрицание в обратной ссылке).

Протестировано на 1000000 итераций:

  1. 0,0245740413665 сек.
  2. 3,3793921470642 сек.
person Maxim Rysevets    schedule 14.05.2021

Я наткнулся на этот пост, когда искал помощь с моим шаблоном, соответствующим этому:

value="long text with \"quoted values\" and more"

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

\bvalue\s*=\s*(["'])(?:(?!(?<!\\)\1).)*\1

Бонусная информация

Возможно, шаблон, который вы здесь ищете, имеет ту же цель, что и мой, поэтому я также поделюсь своим окончательным решением. Мне нужно сопоставить пару пар ключ-значение в том же формате, в котором html-атрибуты обычно перечислены в узле, например: one="first" two="second".

Следующее регулярное выражение будет соответствовать этому и назовет группы захвата key и value:

\b(?P<key>[^=\s]*)\s*=\s*(["'])(?P<value>(?:(?!(?<!\\)\2).)*)\2
person KohlerDominik    schedule 12.07.2021