Lookbehind - неподходящий инструмент для этой работы. Попробуйте вместо этого:
Regex r = new Regex(
@"\[((?>(?:[^y\[\]\\]|\\.)*)y(?>(?:[^\[\]\\]|\\.)*))\]");
string s1 = @"[\[x\]]\]\[[\[y\]]";
Console.WriteLine(s1);
Console.WriteLine(r.Replace(s1, @"%$1%"));
Console.WriteLine();
string s2 = @"[\[x\]]\]\[[1234(\[abcycba\]\y\y)]";
Console.WriteLine(s2);
Console.WriteLine(r.Replace(s2, @"%$1%"));
результат:
[\[x\]]\]\[[\[y\]]
[\[x\]]\]\[%\[y\]%
[\[x\]]\]\[[1234(\[abcycba\]\y\y)]
[\[x\]]\]\[%1234(\[abcycba\]\y\y)%
(я заменил скобки на %
вместо того, чтобы удалить их, чтобы было легче увидеть, что именно заменяется.)
(?:\\.|[^y\[\]\\])*
соответствует нулю или более из (1) обратной косой черты, за которой следует любой символ, или (2) чего-либо, кроме «y», квадратной скобки или обратной косой черты. Если следующим символом является 'y', оно расходуется, и (?:\\.|[^\[\]\\])*
соответствует любым оставшимся символам до следующей неэкранированной скобки. Включение обеих скобок в класс отрицанных символов (вместе с обратной косой чертой) обеспечивает соответствие только самого внутреннего набора скобок без экранирования.
Также важно, чтобы вы использовали атомные группы - т.е., (?>...)
; это предотвращает возврат, который, как мы знаем, бесполезен и может вызвать серьезные проблемы с производительностью, когда регулярное выражение используется для строк, которые не содержат совпадений.
В альтернативном подходе можно использовать предпросмотр, чтобы утверждать наличие символа y, а затем использовать гораздо более простой (?>(?:\\.|[^\[\]\\])*)
, чтобы использовать символы в скобках. Проблема в том, что вы сейчас делаете два прохода над строкой, и может быть непросто убедиться, что заглядывающая сторона не смотрит слишком далеко вперед или недостаточно далеко. Выполнение всей работы за один проход значительно упрощает отслеживание того, где вы находитесь на каждом этапе процесса сопоставления.