TL; DR: Использование захвата (и, в частности, балансирующих групп) внутри .NET lookbehind изменяет полученные захваты, хотя это не должно иметь значения. Что происходит с .NET lookbehinds, который нарушает ожидаемое поведение?
Я пытался найти ответ на этот другой вопрос, как повод поиграть с группами балансировки .NET. Однако я не могу заставить их работать внутри переменной длины.
Прежде всего, обратите внимание, что я не намерен использовать это конкретное решение продуктивно. Это больше по академическим причинам, потому что я чувствую, что что-то происходит с переменным размером lookbehind, о котором я не знаю. И зная, что это может пригодиться в будущем, когда мне действительно нужно использовать что-то вроде этого, чтобы решить проблему.
Рассмотрим этот вход:
~(a b (c) d (e f (g) h) i) j (k (l (m) n) p) q
Цель состоит в том, чтобы сопоставить все буквы, которые находятся в круглых скобках, которым предшествует ~
, не важно, как глубоко вниз (так что все от a
до i
). Моя попытка состояла в том, чтобы проверить правильное положение в lookbehind, чтобы я мог получить все буквы в одном вызове Matches
. Вот мой шаблон:
(?<=~[(](?:[^()]*|(?<Depth>[(])|(?<-Depth>[)]))*)[a-z]
В lookbehind я пытаюсь найти ~(
, а затем я использую названный стек группы Depth
для подсчета посторонних открывающих круглых скобок. Пока скобка, открытая в ~(
, никогда не закрывается, lookbehind должен совпадать. Если достигнута закрывающая скобка, (?<-Depth>...)
не может ничего вытащить из стека, и lookbehind должен завершиться ошибкой (то есть для всех букв из j
). К сожалению, это не работает. Вместо этого я сопоставляю a
, b
, c
, e
, f
, g
и m
. Итак, только эти:
~(a b (c) _ (e f (g) _) _) _ (_ (_ (m) _) _) _
Это похоже на то, что lookbehind не может сравниться ни с чем, как только я закрыл одну круглую скобку, , если я не вернусь к самому высокому уровню вложенности, к которому я был раньше.
Хорошо, это может означать, что с моим регулярным выражением есть что-то странное, или я не правильно понял балансирующие группы. Но потом я попробовал это без взгляда. Я создал строку для каждой буквы:
~(z b (c) d (e f (x) y) g) h (i (j (k) l) m) n
~(a z (c) d (e f (x) y) g) h (i (j (k) l) m) n
~(a b (z) d (e f (x) y) g) h (i (j (k) l) m) n
....
~(a b (c) d (e f (x) y) g) h (i (j (k) l) z) n
~(a b (c) d (e f (x) y) g) h (i (j (k) l) m) z
И использовал этот шаблон для каждого из них:
~[(](?:[^()]*|(?<Depth>[(])|(?<-Depth>[)]))*z
И при желании все случаи совпадают, где z
заменяет букву между a
и i
, а все случаи после этого терпят неудачу.
Итак, что делает (переменная длина) lookbehind, что нарушает это использование балансирующих групп? Я пытался исследовать это весь вечер (и нашел такие страницы, как этот), но я не мог найти ни одного использования этого в lookbehind.
Я также был бы рад, если бы кто-то мог связать меня с некоторой подробной информацией о том, как механизм .NET regex обрабатывает специфичные для .NET функции. Я нашел эту удивительную статью, но, похоже, она не выглядит, например, в (переменной длины) lookbehind.