Regex: повторные группы захвата - PullRequest
10 голосов
/ 03 июля 2010

Я должен проанализировать некоторые таблицы из текстового файла ASCII.Вот частичный пример:

QSMDRYCELL   11.00   11.10   11.00   11.00    -.90      11     11000     1.212
RECKITTBEN  192.50  209.00  192.50  201.80    5.21      34      2850     5.707
RUPALIINS   150.00  159.00  150.00  156.25    6.29       4        80      .125
SALAMCRST   164.00  164.75  163.00  163.25    -.45      80      8250    13.505
SINGERBD    779.75  779.75  770.00  773.00    -.89       8        95      .735
SONARBAINS   68.00   69.00   67.50   68.00     .74      11      3050     2.077

Таблица состоит из 1 столбца текста и 8 столбцов чисел с плавающей запятой.Я хотел бы захватить каждый столбец через регулярное выражение.

Я довольно плохо знаком с регулярными выражениями.Вот неправильный шаблон регулярных выражений, который я придумал:

(\S+)\s+(\s+[\d\.\-]+){8}

Но шаблон захватывает только первый и последний столбцы.RegexBuddy также выдает следующее предупреждение:

Вы повторили саму группу захвата.Группа будет захватывать только последнюю итерацию.Поместите группу захвата вокруг повторяющейся группы, чтобы захватить все итерации.

Я ознакомился с их файлом справки, но не знаю, как решить эту проблему.* Как я могу захватить каждый столбец отдельно?

Ответы [ 3 ]

13 голосов
/ 03 июля 2010

В C # (изменено с в этом примере ):

string input = "QSMDRYCELL   11.00   11.10   11.00   11.00    -.90      11     11000     1.212";
string pattern = @"^(\S+)\s+(\s+[\d.-]+){8}$";
Match match = Regex.Match(input, pattern, RegexOptions.MultiLine);
if (match.Success) {
   Console.WriteLine("Matched text: {0}", match.Value);
   for (int ctr = 1; ctr < match.Groups.Count; ctr++) {
      Console.WriteLine("   Group {0}:  {1}", ctr, match.Groups[ctr].Value);
      int captureCtr = 0;
      foreach (Capture capture in match.Groups[ctr].Captures) {
         Console.WriteLine("      Capture {0}: {1}", 
                           captureCtr, capture.Value);
         captureCtr++; 
      }
   }
}

Выход:

Matched text: QSMDRYCELL   11.00   11.10   11.00   11.00    -.90      11     11000     1.212
...
    Group 2:      1.212
         Capture 0:  11.00
         Capture 1:    11.10
         Capture 2:    11.00
...etc.
4 голосов
/ 02 января 2011

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

Как описано в вопрос 1313332 , получение этих множественных совпадений обычно невозможно с регулярным выражением, хотя .NET и Perl 6 поддерживают его.

Предупреждение говорит о том, что вы можете поместить другую группу вокруг всего набора, например:

(\S+)\s+((\s+[\d\.\-]+){8})

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

4 голосов
/ 03 июля 2010

К сожалению, вам нужно повторить (…) 8 раз, чтобы получить каждый столбец отдельно.

^(\S+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)$

Если код возможен, вы можете сначала сопоставить эти числовые столбцы в целом

>>> rx1 = re.compile(r'^(\S+)\s+((?:[-.\d]+\s+){7}[-.\d]+)$', re.M)
>>> allres = rx1.findall(theAsciiText)

затем разбить столбцы на пробелы

>>> [[p] + q.split() for p, q in allres]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...