Regex: повторные группы захвата
Я должен проанализировать некоторые таблицы из текстового файла 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 ответа
В 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.
К сожалению, вам нужно повторить (…)
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]
Если вы хотите знать, для чего выводится предупреждение, это потому, что ваша группа захвата совпадает несколько раз (8, как вы указали), но переменная захвата может иметь только одно значение. Ему присваивается последнее найденное значение.
Как описано в вопросе 1313332, получение этих множественных совпадений обычно невозможно с помощью регулярного выражения, хотя.NET и Perl 6 поддерживают его.
Предупреждение говорит о том, что вы можете поместить другую группу вокруг всего набора, например так:
(\S+)\s+((\s+[\d\.\-]+){8})
После этого вы сможете увидеть все столбцы, но, конечно, они не будут разделены. Поскольку, как правило, невозможно захватить их по отдельности, более распространенным намерением является захват всего этого, и предупреждение помогает напомнить вам об этом.