Отрицание обратной ссылки в регулярных выражениях
Если строка имеет этот прогнозируемый формат:
value = "hello and good morning"
Где " (цитаты) также могут быть" (одинарные кавычки), а закрывающий символ ("или") будет таким же, как и начальный. Я хочу сопоставить строку между кавычками.
\bvalue\s*=\s*(["'])([^\1]*)\1
(две \ s разрешают пробелы возле знака =)
Первая "захваченная группа" (внутри первой пары скобок) - должна соответствовать открывающей кавычке, которая должна быть либо ", либо" затем - я должен разрешить любое количество символов, которые не были захвачены в первой группе, а затем я ожидаю, что символ, захваченный в группе (кавычки).
(требуемая строка должна быть записана во второй группе захвата).
Это не работает, хотя.
Это делает:
\bvalue\s*=\s*(['"])([^"']*)["']
но я хочу убедиться, что и кавычка открытия и закрытия (либо двойная, либо одинарная) одинаковы.
РЕДАКТИРОВАТЬ
Цель состояла в том, чтобы в основном получить открывающий тег якоря, у которого есть определенное имя класса, включенное в его атрибут класса, и я хотел охватить редкий случай атрибута класса, включающего (') или (()).
Следуя всем советам здесь, я использовал шаблон:
<\s*\ba\b[^<>]+\bclass\s*=\s*("|'|\\"|\\')(?:(?!\1).)*\s*classname\s*(?:(?!\1).)*\1[^>]*>
Значение:
Найдите метку-открытый знак.
Разрешить любые пробелы.
Найдите слово а.
Разрешить любой не закрывающий тег.
Найти "класс (любые пробелы) = (любые пробелы)"
Получить вводные кавычки, одно из следующих: ("или" или \"или \').
Из ответа Алана Мура: разрешите любые символы, которые не являются открывающими кавычками.
найти имя класса
Разрешить любые символы, которые не являются открывающими кавычками.
Найдите заключительную цитату, которая совпадает с открытием.
Разрешить любые символы раскрывающихся тегов.
Найдите закрывающий тег char.
6 ответов
Вместо отрицательного класса символов вы должны использовать отрицательный взгляд:
\bvalue\s*=\s*(["'])(?:(?!\1).)*\1
(?:(?!\1).)*
потребляет по одному символу за раз, после того, как предвестник подтвердил, что персонаж не соответствует тому, что было найдено группой захвата, (["''])
, Класс символов, отрицательный или нет, может соответствовать только одному символу за раз. Насколько движок регулярных выражений знает, \1
может представлять любое количество символов, и нет никакого способа убедить его в том, что \1
будет содержать только "
или же '
в этом случае. Таким образом, вы должны пойти с более общим (и менее читаемым) решением.
Не зная, для чего вам нужна информация (или даже того, на каком языке или инструменте вы используете это регулярное выражение), я могу предложить множество путей.
Используя эти строки:
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. Вы можете выяснить, какой тип кавычек используется, получив первый (или последний) символ.
Если вам нужно, чтобы некоторые из этих вещей были в конкретных группах совпадений, приведите более конкретные примеры (и включите вещи, которые не должны работать, но выглядят так, как будто они близки)
Пожалуйста, спросите, хотите ли вы воспользоваться этим маршрутом и вам нужна дополнительная помощь?
Отвечая на этот вопрос Как использовать числовую ссылку в забытом наборе?
здесь, потому что он был отмечен как точная копия этого.
Не могу указать группу захвата внутри класса.
Что можно сделать, так это указать символ в отрицательном утверждении, например
(["'])((?:(?!\1)[\S\s])*)(\1)
Расширенный
( ["'] ) # (1)
( # (2 start)
(?:
(?! \1 )
[\S\s]
)*
) # (2 end)
( \1 ) # (3)
Обратите внимание, что в исходном сообщении [^char]
обычно соответствует и переносам строк
, но, поскольку это JavaScript (старый JS), точку использовать нельзя.
Использовать[\S\s]
вместо этого, что соответствует любому символу.
Я наткнулся на этот пост, когда искал помощь с моим шаблоном, соответствующим этому:
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
Пример замены:
"markdown *text*"
к:
"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 итерациях:
- 0,0245740413665 сек.
- 3.3793921470642 сек.