Я пытаюсь удалить текст, который является в круглых скобках (наряду с самими круглыми скобками), но испытывает затруднения из-за сценария, где существуют круглые скобки в круглых скобках. Это - метод, который я использую (в Ruby):
sentence.gsub(/\(.*?\)/, "")
и это хорошо работает, пока у меня нет предложения, такого как:
"This is (a test (string))"
Затем вышеупомянутые дроссели. У кого-либо есть какая-либо идея, как сделать это? Я полностью озадачен.
Один из вариантов - заменить изнутри скобки:
x = string.dup
while x.gsub!(/\([^()]*\)/,""); end
x
Проблема в том, что языки, содержащие вложенные скобки (или действительно что-либо вложенное, IOW все, что требует рекурсии) не являются регулярными, они, по крайней мере, контекстно-свободны. Это означает, что они не могут быть описаны с помощью обычной грамматики. Регулярные выражения - это компактное обозначение регулярных грамматик. Следовательно, вложенные круглые скобки не могут быть описаны регулярными выражениями.
Однако мы не говорим здесь о регулярных выражениях, мы говорим о Regexp
s. Хотя их семантика и синтаксис (очень) слабо основаны на регулярных выражениях, они совершенно разные и особенно гораздо более мощные. В зависимости от конкретной разновидности Regexp
, которую вы используете, они могут или не могут выражать рекурсию и, таким образом, анализировать вложенные скобки. Perl Regex
, например , может анализировать вложенные скобки. Я не уверен, может ли Ruby Regexp
, но меня это действительно не волнует, потому что способ, которым Regexp
более мощный, чем регулярные выражения, обычно достигается за счет использования все большего и большего количества синтаксиса на них.
Это превращает регулярные выражения, которые должны быть простыми, в непонятных монстров. (Если вы можете с первого взгляда сказать, что делает Perl Regex
, опубликованный @Anon, тогда сделайте это. Но я не могу и поэтому предпочитаю не использовать его.)
Я предпочитаю использовать более мощный парсер, чем сложный Regexp
.
В этом случае у вас есть контекстно-свободный язык, поэтому вы можете использовать очень простой рекурсивный анализатор спуска. Вы можете еще больше упростить синтаксический анализатор рекурсивного спуска, обработав те части, которые являются регулярными, с помощью регулярного выражения. Наконец, если вы замените рекурсию в синтаксическом анализаторе рекурсивного спуска на итерацию + мутацию и грамотно воспользуетесь логической семантикой Ruby, весь синтаксический анализатор будет в основном сжат до этой единственной строки:
while str.gsub!(/\([^()]*?\)/, ''); end
Что я не считаю слишком плохим.
Вот все, с дополнительным удалением повторяющихся пробелов и (конечно) набором тестов:
require 'test/unit'
class TestParenthesesRemoval < Test::Unit::TestCase
def test_that_it_removes_even_deeply_nested_parentheses
str = 'This is (was?) some ((heavily) parenthesized (but not overly so
(I hope))) text with (superflous) parentheses: )(.'
res = 'This is some text with parentheses: )(.'
while str.gsub!(/\([^()]*?\)/, ''); end
str.squeeze!(' ')
assert_equal res, str
end
end
Похоже, что нужно быть жадным, убрав ?
>> "This is (a test (string))".gsub(/\(.*\)/, "")
=> "This is "
Это заставляет перейти к последнему )
, а не к первому. Но это не захватывает гнездо, потому что регекс не может этого сделать.
Следующий регекс Perl будет соответствовать сбалансированным скобкам:
/(\((?:[^\(\)]++|(?1))*\))/
Однако к этому моменту вы технически больше не используете "регулярные" выражения.
jleedev ответ сработает, если на самом крайнем уровне находится только один набор скобок; в этом случае делать выражение для внутрений этих скобок жадно.
Однако, и, возможно, немного удивительно, регеxps, как они определены в Perl, Java, Ruby и некоторых других языках, но также grep
и sed
не подходят для решения этой проблемы. Нет регэкспа для решения общего случая вложенных разделителей. Это одна из причин, по которой люди на SO кричат на вас, когда вы хотите использовать регеxp для обработки HTML или XML.
Интересно, что создатель языка Lua решил эту проблему, добавив новый шаблон соответствия к довольно простому в остальном языку шаблонов. Посмотрите на нижнюю часть строк в http://www.lua.org/pil/20.2.html !
.