正则表达式:重复捕获组

inv*_*ass 12 .net c# 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
Run Code Online (Sandbox Code Playgroud)

该表由1列文本和8列浮点数组成.我想通过正则表达式捕获每一列.

我对正则表达式很新.这是我提出的错误的正则表达式模式:

(\S+)\s+(\s+[\d\.\-]+){8}
Run Code Online (Sandbox Code Playgroud)

但该模式仅捕获第一列和最后一列.RegexBuddy也会发出以下警告:

您重复了捕获组本身.该组将仅捕获最后一次迭代.在重复组周围放置捕获组以捕获所有迭代.

我已经咨询了他们的帮助文件,但我不知道如何解决这个问题.

如何单独捕获每列?

Tim*_*ker 14

在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++; 
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

输出:

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.
Run Code Online (Sandbox Code Playgroud)

  • "捕获"是一个很好的功能,但在这里似乎有些过分.为什么不在空格上分割每一行?即使您使用正则表达式来验证行的格式,它仍然不那么重要. (2认同)

ken*_*ytm 5

不幸的是,您需要重复(\xe2\x80\xa6)8 次才能分别获取每一列。

\n\n
^(\\S+)\\s+([-.\\d]+)\\s+([-.\\d]+)\\s+([-.\\d]+)\\s+([-.\\d]+)\\s+([-.\\d]+)\\s+([-.\\d]+)\\s+([-.\\d]+)\\s+([-.\\d]+)$\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果代码可行,您可以首先将这些数字列作为一个整体进行匹配

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

然后用空格分割列

\n\n
>>> [[p] + q.split() for p, q in allres]\n
Run Code Online (Sandbox Code Playgroud)\n

  • .NET 的特殊之处在于它保留中间捕获!请参阅蒂姆的回答和http://stackoverflow.com/questions/3029127/is-there-a-regex-flavor-that-allows-me-to-count-the-number-of-repetitions-matched/ (3认同)

Sam*_*man 5

如果您想知道出现警告的原因,那是因为您的捕获组匹配多次(如您指定的那样,为 8 次),但捕获变量只能有一个值。它被分配最后一个匹配的值。

正如问题 1313332中所述,使用正则表达式通常不可能检索这些多个匹配项,尽管 .NET 和 Perl 6 对此有一些支持。

该警告建议您可以在整个集合周围放置另一组,如下所示:

(\S+)\s+((\s+[\d\.\-]+){8})
Run Code Online (Sandbox Code Playgroud)

然后您将能够看到所有列,但它们当然不会被分开。因为通常不可能单独捕获它们,所以更常见的目的是捕获所有这些,并且警告有助于提醒您这一点。