Извлечение всех перекрывающихся подстрок между вложенными совпадающими круглыми скобками с помощью регулярного выражения .NET

Я пытаюсь разобрать математические выражения с вложенными скобками:

(1 * (2 - 3)) + 4

Я хочу заключить каждое выражение в скобки, например:

  • (1 * (2 - 3))
  • (2 - 3)

Используя это выражение: (.*?\))(?=($|[^(]+)) Я получаю такой результат:

(1 * (2 - 3)

)

И используя это выражение: \(.*?\) Я получаю такой результат:

(1 * (2 - 3) 

Но ничего не работает правильно. Как я могу зациклить выражение внутри?


person Vladislav Horbachov    schedule 19.04.2021    source источник


Ответы (2)


Вы можете использовать

(?=(\((?>[^()]+|(?<c>)\(|(?<-c>)\))*(?(c)(?!))\)))

См. regex demo . Подробности:

  • (?= - a positive lookahead:
    • (\((?>[^()]+|(?<c>)\(|(?<-c>)\))*(?(c)(?!))\))) - Group 1:
      • \( - a ( char
      • (?>[^()]+|(?<c>)\(|(?<-c>)\))* - ноль или более повторений любого одного или нескольких символов, кроме ( и ), или символа ( (со значением, помещенным в стек группы c), или символа ) (со значением, извлеченным из стека группы c)
      • (?(c)(?!)) - если стек группы c не пуст, сбой и возврат
      • \) - ) символ.

См. демонстрацию C #:

var text = "(1 * (2 - 3)) + 4";
var pattern = @"(?=(\((?>[^()]+|(?<c>)\(|(?<-c>)\))*(?(c)(?!))\)))";
var results = Regex.Matches(text, pattern)
    .Cast<Match>()
    .Select(m => m.Groups[1].Value)
    .ToList();
Console.WriteLine(String.Join(", ", results));
// => (1 * (2 - 3)), (2 - 3)
person Wiktor Stribiżew    schedule 19.04.2021
comment
интересно, это хорошо работает, когда я запускаю его в Linqpad, но в RegexBuddy он не соответствует, даже если он компилируется нормально - person gordy; 20.04.2021
comment
@gordy Не используйте его в Regex *, используйте его в C #. Это регулярное выражение, совместимое с .NET. - person Wiktor Stribiżew; 20.04.2021

Обычным способом было бы использовать рекурсивное регулярное выражение, но, к сожалению, эта возможность не поддерживается в C # Regex. Кроме того, вы можете вручную проанализировать строку (и для этого есть код C #, предоставленный в этом PAQ).

person gordy    schedule 19.04.2021
comment
Пожалуйста, не ссылайтесь на существующие ответы, подобные этому. Если этот вопрос дублирует другой, отметьте его как таковой. - person Enigmativity; 20.04.2021
comment
@Enigmativity есть ли для этого рекомендации сообщества? это не повторяющийся вопрос, поскольку они конкретно спрашивали, как это сделать с помощью регулярного выражения, но ответ, вероятно, актуален - я подумал, что связывание будет лучше, чем копирование и вставка ответа здесь, поскольку контекст, вероятно, также полезен - person gordy; 20.04.2021
comment
Если у вас нет чего-то существенного в вашем ответе (т.е. он может стоять отдельно), тогда это должен быть комментарий. C # Regex не поддерживает рекурсивные выражения, я предлагаю проанализировать это вручную, чтобы ответить на этот вопрос? - person Enigmativity; 20.04.2021
comment
meta.stackoverflow.com/questions/265552/ - person Enigmativity; 20.04.2021