Удаление текста в скобках (скобки в скобках, вероятно) - PullRequest
6 голосов
/ 23 декабря 2009

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

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

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

"This is (a test (string))"

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

Ответы [ 5 ]

10 голосов
/ 23 декабря 2009

Один подход состоит в том, чтобы заменить заключенные в скобки группы изнутри:

x = string.dup
while x.gsub!(/\([^()]*\)/,""); end
x
10 голосов
/ 23 декабря 2009

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

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

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

2 голосов
/ 23 декабря 2009

Проблема в том, что языки, содержащие вложенные скобки (или даже что-либо вложенные, 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
1 голос
/ 23 декабря 2009

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

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

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

0 голосов
/ 23 декабря 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...