Проблема с этим состоит в том, что языки, содержащие вложенные скобки (или действительно ничего вложен, IOW ничего, что требует рекурсии) не являются регулярные, они, по крайней мере, свободны от контекста. Это означает, что они не могут быть описаны обычной грамматикой. Регулярные выражения являются компактными обозначениями для регулярных грамматик. Ergo, вложенные круглые скобки не могут быть описаны регулярными выражениями.
Однако мы не говорим о регулярных выражениях здесь, мы говорим о Regexp
. Хотя их семантика и синтаксис (очень) свободно основаны на регулярных выражениях, они совершенно разные и особенно значительно более мощные. В зависимости от конкретного вкуса Regexp
, который вы используете, они могут или не могут выражать рекурсию и, следовательно, анализировать вложенные круглые скобки. Perl Regex
, например может разобрать вложенные круглые скобки.Я не уверен, может ли Ruby's 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
Что делать, если есть неравное количество открывающих и закрывающих тегов, как в '(Foo) бар) 'или если нет пар, например, в' foo '(bar'? – Gumbo
Мне не нужно учитывать этот сценарий. – TenJack