С# Regex – как удалить несколько парных скобок из строки

Я пытаюсь понять, как использовать регулярные выражения С# для удаления всех экземпляров парных скобок из строки. Скобки и весь текст между ними должны быть удалены. Скобки не всегда находятся на одной строке. Кроме того, это могут быть вложенные скобки. Пример строки будет

This is a (string). I would like all of the (parentheses
to be removed). This (is) a string. Nested ((parentheses) should) also
be removed. (Thanks) for your help.

Желаемый результат должен быть следующим:

This is a . I would like all of the . This  a string. Nested  also
be removed.  for your help.

person Matt Brandon    schedule 18.01.2013    source источник
comment
Можете ли вы добавить желаемый результат?   -  person Ryan Gates    schedule 19.01.2013
comment
Конечно. Я обновлю пост.   -  person Matt Brandon    schedule 19.01.2013
comment
... или здесь: stackoverflow.com/questions/133601/   -  person James Boutcher    schedule 19.01.2013
comment
Я не думаю, что это дубликат, так как я также спрашиваю об обычных невложенных скобках и скобках, которые охватывают более одной строки в дополнение к вложенной части. Если вложенная часть не может быть выполнена, меня все равно интересуют две другие.   -  person Matt Brandon    schedule 19.01.2013
comment
Как насчет непарных скобок?   -  person David R Tribble    schedule 19.01.2013
comment
На повторяющийся вопрос нет ответа, а ответ ЕСТЬ есть.   -  person JDB still remembers Monica    schedule 19.01.2013


Ответы (4)


К счастью, .NET допускает рекурсию в регулярных выражениях (см. Балансировка определений групп). ):

Regex regexObj = new Regex(
    @"\(              # Match an opening parenthesis.
      (?>             # Then either match (possessively):
       [^()]+         #  any characters except parentheses
      |               # or
       \( (?<Depth>)  #  an opening paren (and increase the parens counter)
      |               # or
       \) (?<-Depth>) #  a closing paren (and decrease the parens counter).
      )*              # Repeat as needed.
     (?(Depth)(?!))   # Assert that the parens counter is at zero.
     \)               # Then match a closing parenthesis.",
    RegexOptions.IgnorePatternWhitespace);

В случае, если кому-то интересно: «счетчик скобок» никогда не может опускаться ниже нуля (в противном случае <?-Depth> не удастся), поэтому, даже если круглые скобки «сбалансированы», но не совпадают правильно (например, ()))((()), это регулярное выражение не будет обмануто.

Для получения дополнительной информации прочитайте прекрасную книгу Джеффри Фридла "Мастерство регулярных выражений" (стр. 436).

person Tim Pietzcker    schedule 18.01.2013
comment
@MattBrandon. В .NET это можно сделать еще проще: Балансирующие определения групп. - person JDB still remembers Monica; 19.01.2013
comment
@Cyborgx37: Что вы имеете в виду под еще более простым способом? Я использую именно тот метод, на который вы ссылались (спасибо за ссылку - я включил ее в свой ответ). Я просто использую другое имя для счетчика (Depth вместо Open), что, конечно, не имеет значения. - person Tim Pietzcker; 19.01.2013
comment
Кроме того, я обычно не беспокоюсь о минусах, но в этом случае мне было бы очень интересно узнать, почему этот ответ был сочтен кем-то бесполезным. - person Tim Pietzcker; 19.01.2013

Однако вы можете повторно заменять /\([^\)\(]*\)/g пустой строкой, пока не будет найдено больше совпадений.

person flup    schedule 18.01.2013

Как правило, это не вариант. Однако у Microsoft есть некоторые расширения стандартных регулярных выражений. Этого можно добиться с помощью конструкций группировки, даже если это быстрее кодировать как алгоритм, чем читать и понимать объяснение Microsoft их расширения.

person Alexandre Rafalovitch    schedule 18.01.2013
comment
На самом деле сегодня я решил эту проблему, просто написав алгоритм для выполнения этой работы. Однако мне стало очень любопытно, можно ли это сделать с помощью Regex. - person Matt Brandon; 19.01.2013

Как насчет этого: Regex Replace, похоже, помогает.

string Remove(string s, char begin, char end)
{
    Regex regex = new Regex(string.Format("\\{0}.*?\\{1}", begin, end));
    return regex.Replace(s, string.Empty);
}


string s = "Hello (my name) is (brian)"
s = Remove(s, '(', ')');

Выход будет:

"Hello is"
person Botonomous    schedule 18.01.2013
comment
Я думаю, вам лучше использовать Regex.Escape() вместо "\\{0}" - person JDB still remembers Monica; 19.01.2013