2009-12-23 3 views
6

Я пытаюсь удалить текст, который находится в круглых скобках (вместе с самими скобками), но у меня возникли проблемы со сценарием, где в круглых скобках есть круглые скобки. Это метод я использую (в Ruby):Удаление текста в круглых скобках (круглые скобки в круглых скобках prob)

sentence.gsub(/\(.*?\)/, "") 

и это работает прекрасно, пока у меня есть предложение, такие как:

"This is (a test (string))" 

Тогда вышеупомянутые дроссели. Кто-нибудь знает, как это сделать? Я полностью в тупике.

+1

Что делать, если есть неравное количество открывающих и закрывающих тегов, как в '(Foo) бар) 'или если нет пар, например, в' foo '(bar'? – Gumbo

+0

Мне не нужно учитывать этот сценарий. – TenJack

ответ

10

Один Approch должен заменить вводные группы изнутри:

x = string.dup 
while x.gsub!(/\([^()]*\)/,""); end 
x 
10

Похоже, вы должны быть жадным, удалив ?

>> "This is (a test (string))".gsub(/\(.*\)/, "") 
=> "This is " 

Это делает его переход к последнему ) вместо первого. Однако он не фиксирует вложенность, поскольку регулярное выражение не может этого сделать.

+1

Не делает то, что нужно для этого (в круглых скобках) и (так это) text';) – Juliet

+1

Избегание круглых скобок никогда не было частью проблемы; OP сделал это, но обратная косая черта не появилась, потому что (а) он не применял правильное форматирование исходного кода. –

0

Ответ jleedev будет работать, если на самом удаленном уровне имеется только один набор скобок; в этом случае, делая выражение для внутренней стороны этих круглых скобок жадным, должен сделать трюк.

Однако, и, возможно, немного удивительно, что регулярные выражения, как это определено в Perl, Java, Ruby и некоторых других языках, но и grep и sed не подходят для решения этой проблемы. Нет никакого регулярного выражения для рассмотрения общего случая вложенных разделителей. Это одна из причин, по которым люди на вас злятся, когда вы хотите использовать регулярное выражение для обработки HTML или XML.

Интересно, что создатель языка Lua обратился к этой проблеме, добавив новый шаблон соответствия к другому довольно простому языку шаблона. Посмотрите на нижнюю часть строк в http://www.lua.org/pil/20.2.html!

+1

Рекурсивные шаблоны Perl могут обрабатывать вложенные разделители. – newacct

+0

К сожалению! Исправлено, спасибо. –

1

Следующий Perl регулярное выражение будет соответствовать сбалансированные скобки:

/(\((?:[^\(\)]++|(?1))*\))/ 

Однако, к тому времени, вы получите этот момент, вы не технически с помощью «обычных» выражений больше.

+3

Более того, вы больше не используете Ruby. –

+0

это красиво! После этого я нашел версию Ruby (1.9/Oniguruma):/(? \ ((?: [^ \ (\)] ++ | \ g ) * \)) / –

2

Проблема с этим состоит в том, что языки, содержащие вложенные скобки (или действительно ничего вложен, 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 
Смежные вопросы