Проблема группировки регулярных выражений - PullRequest
0 голосов
/ 13 мая 2009

У меня есть некоторые текстовые данные в этом формате:

MI
00
3

MD
1
0.0000
MD
2
0.0000
MD
3
0.0000

Этот блок может быть повторен, и число MD является переменным (но всегда> = 1), и для каждого из них необходимо записать следующие числовые значения.

У меня есть регулярное выражение, которое соответствует каждому MD за MI, но оно будет захватывать только последний MD. Можно ли захватить каждого МД, не зная заранее, сколько их?

РЕДАКТИРОВАТЬ : По запросам ... Регулярное выражение ниже; важная часть моего вопроса остается «могу ли я захватить каждый набор MD?»

MI\r\d\d\r(\d)\r[\s\w]{6}\r(MD\r[\s\d]{2}\r[\s\d\.\-]*\r)+

Мой язык по выбору - C #, но я бы взял ответ на любом языке, потому что это, по крайней мере, дало бы мне начало.

MD - это точка данных из детектора серы с начала 90-х годов.

Ответы [ 5 ]

3 голосов
/ 13 мая 2009

Каждый матч имеет коллекцию групп. В вашем случае Matches [0] .Groups [1] будет соответствовать записям MD, например, "MD \ n1 \ n0.0000MD \ n2 \ n0.0000MD \ n3 \ n0.0000".

Каждая группа имеет коллекцию Captures , которую вы можете перебрать, чтобы найти все экземпляры MD. Это даст вам одну строку на MD, поэтому Matches [0] .Groups [1] .Captures [0] будет иметь значение «MD \ n1 \ n0.0000».

РЕДАКТИРОВАТЬ: хотя вы уже приняли ответ, вот способ проанализировать все за один раз:

string pat = @"MI[\r\n]*(?<MI1>\d\d)[\r\n]*(?<MI2>\d+)[\r\n]*" +
    @"(MD[\r\n]*(?<MD1>\d+)*[\r\n]*(?<MD2>[\d\.\-]+)+[\r\n]*)*";

var r = new Regex(pat);
foreach (Match match in r.Matches(text))
{
    Console.WriteLine("MI v1:{0} v2:{1}", 
         match.Groups["MI1"], match.Groups["MI2"]);

    if (match.Groups.Count > 2)
        for (var i = 0; i < match.Groups["MD1"].Captures.Count; i++)
            Console.WriteLine("  MD v1:{0} v2:{1}", 
                match.Groups["MD1"].Captures[i], 
                match.Groups["MD2"].Captures[i]);
}

Это тестовый текст, который я использовал:

MI
00
3

MD
1
0.1000
MD
2
0.2000
MD
3
0.3000

MI
12
5

MI
24
5

MD
1
0.1000

Вывод:

MI v1:00 v2:3
  MD v1:1 v2:0.1000
  MD v1:2 v2:0.2000
  MD v1:3 v2:0.3000
MI v1:12 v2:5
MI v1:24 v2:5
  MD v1:1 v2:0.1000
2 голосов
/ 13 мая 2009

Возможно, но это займет более одного прохода по данным. Группа регулярных выражений может содержать только один кусок информации за матч. Таким образом, вы могли бы иметь группу MD и найти все ваши совпадения MD или группу MI, которая содержала группу MD и которая нашла бы все ваши совпадения MI ... но группа MD не будет выделена.

Одно решение - это вложенные вызовы регулярных выражений, при этом первое находит каждую группу MI, а второе - каждую группу MD в группе MI.

0 голосов
/ 13 мая 2009

Я бы порекомендовал вам реализовать конечный автомат для этой задачи.

Но вот регулярное выражение, я думаю, также будет работать:

MI\r\d\d\r(\d)\r\r(MD\r\d\r[0-9\.]+\r?)*
0 голосов
/ 13 мая 2009

Я не эксперт в C #, но в Java вы бы хотели изменить (MD ...) + на ((MD ...) +). Таким образом, вы можете использовать внешнюю пару скобок для захвата всех MD.

0 голосов
/ 13 мая 2009

Я думаю, что это сделает это. По крайней мере, он работает с RegexBuddy с использованием Perl.

MD[^MI]*

Данные только что повторены сверху.

EDIT: Кажется, что это захватывает все MD и начальный MI в своем маленьком блоке.

MI([^MI]*(MD[^MI]*)*)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...