Vim help сообщает, что:
\1 Matches the same string that was matched by */\1* *E65* the first sub-expression in \( and \). {not in Vi} Example: "\([a-z]\).\1" matches "ata", "ehe", "tot", etc.
Похоже, что обратную ссылку можно использовать в шаблоне поиска. Я начал играть с ним и заметил поведение, которое не могу объяснить. Это мой файл:
<paper-input label="Input label"> Some text </paper-input>
<paper-input label="Input label"> Some text </paper-inputa>
<aza> Some text </az>
<az> Some text </az>
<az> Some text </aza>
Я хотел сопоставить строки, в которых совпадают открывающий и закрывающий теги, например:
<paper-input label="Input label"> Some text </paper-input>
<az> Some text </az>
И мое тестовое регулярное выражение:
%s,<\([^ >]\+\).*<\/\1>,,gn
Но это соответствует строкам: 1
, 3
и 4
. То же самое с sed :
$ sed -ne 's,<\([^ >]\+\).*<\/\1>,\0,p' file
<paper-input label="Input label"> Some text </paper-input>
<aza> Some text </az>
<az> Some text </az>
Это: <\([^ >]\+\)
должен быть жадным, и при попытке сопоставить его без \1
в конце все группы будут правильными. Но когда я добавляю \1
, кажется, что <\([^ >]\+\)
становится не жадным и пытается принудительно найти соответствие в 3-й строке . Может кто-нибудь объяснить, почему он соответствует строке 3rd
:
<aza> Some text </az>
Это также демонстрация regex101
ПРИМЕЧАНИЕ Речь идет не о самом регулярном выражении (возможно, есть другой способ сделать это), а о поведении этого регулярного выражения.
3 ответа
Чтобы понять, почему ваше регулярное выражение ведет себя именно так, вам нужно понять, что делает механизм регулярного выражения с возвратом.
Движок будет жадно сопоставлять и потреблять столько символов, сколько сможет. Но если он не находит совпадения, он возвращается и пытается найти другое совпадение, которое все еще удовлетворяет шаблону.
%s,<\([^ >]\+\).*<\/\1>,,gn
Для строки три <aza> Some text </az>
,
Механизм регулярных выражений смотрит на \1 = aza
. и видит, соответствует ли .*</aza>
остальной части строки. Это не так, поэтому он выбирает что-то другое для \1
. В следующий раз он выбирает \1 = az
и проверяет, совпадает ли .*</az>
с остальной частью строки, и делает это. Итак, строка соответствует
(Это упрощенная версия. Я пропустил тот факт, что .*
потенциально может сам выполнять большое количество откатов)
Решить это так же просто, как добавить якорь в регулярное выражение, не позволяя регулярному выражению искать другие значения, которые могли бы удовлетворить \1
. В этом случае достаточно пробела или >
.
Вам нужно добавить \>
, чтобы указать конец слова . Могут быть и другие решения с узорами нулевой ширины, но это усложнит ситуацию.
Кроме того, ваш разделитель ,
, а не /
Который дает:
%s,<\([^ >]\+\)\>.*</\1>,,gn
В настоящее время причина, по которой строка 3 (<aza>
) отображается как совпадение, заключается в том, что термин .*
в вашем регулярном выражении может совпадать в нескольких строках. Итак, строка 3 соответствует, потому что строка 5 имеет закрывающий тег. Чтобы исправить это, заставьте регулярное выражение найти соответствующий закрывающий тег только в той же строке:
%s,<\([^ >]\+\)[^\n]*?<\/\1>,,gn
^^^^^ use [^\n]* instead of .*
Похожие вопросы
Связанные вопросы
Новые вопросы
regex
Регулярные выражения предоставляют декларативный язык для сопоставления шаблонов в строках. Они обычно используются для проверки строк, разбора и преобразования. Укажите язык (PHP, Python и т. д.) или инструмент (grep, VS Code, Google Analytics и т. д.), который вы используете. Не размещайте вопросы, требующие объяснения того, что означает символ или чему будет соответствовать конкретное регулярное выражение.