Проблема в том, что языки, содержащие вложенные скобки (или даже что-либо вложенные, IOW, все, что требует рекурсии), не являются регулярными, они по крайней мере не зависят от контекста. Это означает, что они не могут быть описаны обычной грамматикой. Регулярные выражения являются компактными обозначениями для регулярных грамматик. Поэтому вложенные скобки не могут быть описаны с помощью регулярных выражений.
Однако здесь мы не говорим о регулярных выражениях, мы говорим о Regexp
s. Хотя их семантика и синтаксис (очень) слабо основаны на регулярных выражениях, они довольно разные и особенно гораздо более мощные. В зависимости от конкретной разновидности Regexp
, которую вы используете, они могут или не могут быть в состоянии выразить рекурсию и, таким образом, анализировать вложенные скобки. Perl Regex
, например может разобрать вложенные скобки. Я не уверен, может ли Regexp
Руби, но мне действительно все равно, потому что способ, которым Regexp
является более мощным, чем регулярные выражения, обычно достигается путем добавления к ним все большего и большего количества синтаксиса.
Это превращает регулярные выражения, которые должны быть простыми, в непонятных монстров. (Если вы можете сразу увидеть, что делает Perl Regex
, опубликованный @Anon, то сделайте это. Но я не могу и поэтому предпочитаю не использовать его.)
Я предпочитаю использовать более мощный синтаксический анализатор, а не сложный Regexp
.
В этом случае у вас есть язык без контекста, поэтому вы можете использовать очень простой парсер рекурсивного спуска. Вы можете еще больше упростить свой анализатор рекурсивного спуска, обрабатывая те части, которые являются регулярными с регулярным выражением. Наконец, если вы замените рекурсию в парсере рекурсивного спуска итерацией + мутацией и умело используете булеву семантику Руби, весь парсер будет в основном сжат до этой единственной строки:
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