Написание регулярного выражения для захвата текста между внешними скобками - PullRequest
2 голосов
/ 12 августа 2010

Итак, я пытаюсь проанализировать файл с текстом в следующем формате:

outerkey = (innerkey = innervalue)

Это становится более сложным. Это также допустимо в файле:

outerkey = (innerkey = (twodeepkey = twodeepvalue)(twodeepkey2 = twodeepvalue2))

Итак, я хочу в основном захватить только текст внешнего ключа. Я не могу гарантировать, что весь текст будет в одной строке. Возможно, что значение будет в нескольких строках. И в файле более одного элемента.

Итак, вот мое регулярное выражение:

[^\s=]+\s*=\s*(\(\s*.*\s*\))

Цель для меня - просто заменить первую часть [^\s=]+ ключом, по которому я хочу искать, и я получу весь текст внешней скобки.

Вот проблема. Мое регулярное выражение будет не только захватывать текст, который я хочу захватить, но также захватывать текст из следующей группы, поскольку регулярные выражения жадные. Если вы не сделаете его жадным, то это тоже не сработает, так как он перестанет фиксироваться в первой закрывающей скобке.

В конечном итоге, если у меня есть следующая строка

foo = 
(
  ifoo = ifoov
)

bar =
(
  ibar =
    (iibar = iibarv)
    (iibar2 = iibarv2)
)

Я хочу, чтобы группы совпадали

(
  ifoo = ifoov
)

и

(
  ibar =
    (iibar = iibarv)
    (iibar2 = iibarv2)
)

Прямо сейчас это будет соответствовать

(
  ifoo = ifoov
)

bar =
(
  ibar =
    (iibar = iibarv)
    (iibar2 = iibarv2)
)

Кстати, я запускаю это в многострочном и однострочном режиме.

Есть идеи? Спасибо!

Ответы [ 2 ]

3 голосов
/ 12 августа 2010

Мне удалось адаптировать определение балансирующей группы .NET regex для этой проблемы следующим образом:

Regex r = new Regex(@"(?x) # for sanity!

    (?'Key' [^=\s]* )
    \s*=\s*
    (?'Value'
      (
         (
           [^()]*
           (?'Open'\()
         )+
         (
           [^()]*
           (?'Close-Open'\))
         )+
      )+?
    )
    (?(Open)(?!))

");

Затем мы можем проверить это следующим образом:

var text = @"
foo = 
(
  ifoo = ifoov
)

bar =
(
  ibar =
    (iibar = iibarv)
    (iibar2 = iibarv2)
)

outerkey = (innerkey = (twodeepkey = twodeepvalue)(twodeepkey2 = twodeepvalue2))
";

foreach (Match m in r.Matches(text)) {
  Console.WriteLine("Key: [{0}]", m.Groups["Key"]);
  Console.WriteLine("Value: [{0}]", m.Groups["Value"]);
  Console.WriteLine("-------");
}
Console.WriteLine("That's all folks!");

Это печатает ( как видно на ideone.com ):

Key: [foo]
Value: [(
  ifoo = ifoov
)]
-------
Key: [bar]
Value: [(
  ibar =
    (iibar = iibarv)
    (iibar2 = iibarv2)
)]
-------
Key: [outerkey]
Value: [(innerkey = (twodeepkey = twodeepvalue)(twodeepkey2 = twodeepvalue2))]
-------
That's all folks!

Некоторые незначительные изменения из примера шаблона из документации:

  • Открыто - закрыто - ни одна скобка теперь \( - \) - [^()] вместо < - > - [^<>]
  • Сбалансированная структура повторяется с +? (хотя бы один, но как можно меньше) вместо *
  • «содержимое» сопоставляется до, а не после скобок
2 голосов
/ 12 августа 2010

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

...