正则表达式只匹配一个组

时间:2014-06-12 02:27:25

标签: c# regex delimited-text

我有一个非常古老(并且奇怪分隔)的字符串代表一个表格,我希望在两个“标签”之间得到所有文本(它们是令人厌恶的......在这里,它们充满了他们的荣耀):< / p>

<<<NAME=Test User>>>
<<<DATE=11/06/2014>>>
|||COMMENTS_FOLLOW_UP=\\myserver\Reporter\testu\20140611.rtf|||
|||COMMENTS_APPOINTMENT_LIST=\\myserver\Reporter\testu\COMMENTS_APPOINTMENT_LIST_20140611.rtf|||
~~~ START MONTHLY BREAKDOWN ~~~
### ROW START ###
<<<ACTIVITY=Target Group Support>>>
<<<PERCENTAGE_OF_TIME_TAKEN_FOR_THE_MONTH=25%>>>
### ROW END ###
### ROW START ###
<<<ACTIVITY=Non-target Group Support>>>
<<<PERCENTAGE_OF_TIME_TAKEN_FOR_THE_MONTH=25%>>>
### ROW END ###
### ROW START ###
<<<ACTIVITY=Networking/Guest Speaking Activities>>>
<<<PERCENTAGE_OF_TIME_TAKEN_FOR_THE_MONTH=25%>>>
### ROW END ###
### ROW START ###
<<<ACTIVITY=Processing initial calls, making appointments, completing reports and other tasks>>>
<<<PERCENTAGE_OF_TIME_TAKEN_FOR_THE_MONTH=25%>>>
### ROW END ###
### ROW START ###
<<<ACTIVITY=Total>>>
<<<PERCENTAGE_OF_TIME_TAKEN_FOR_THE_MONTH=100%>>>
### ROW END ###
~~~ END MONTHLY BREAKDOWN ~~~
~~~ START EVENTS ~~~
### ROW START ###
<<<DATE=11/06/2014 12:00:00 AM>>>
<<<EVENT_NAME=Test's Event>>>
<<<NAME_OF_ORGANISATION/GROUP=Tests Org>>>
<<<PARTICIPANT_GROUP=Test>>>
<<<NUMBER_OF_PARTICIPANTS=50>>>
### ROW END ###
~~~ END EVENTS ~~~ 

所以我需要在分隔符~~~ START XXX ~~~~~~ END XXX ~~~

之间获取文字

所以这就是我掀起的模式:~~~ START .+~~~(.*)~~~ END .+~~~;

正如你所看到的,正是一个正则表达的主人,我不是。

注意:我正在使用SingleLine标志。

问题:这与正确的文字匹配,但只返回一个组,即第一个表标记的正文文本组。如何让C#regex-a-tron 9000从第二个匹配组中的 second 标签返回正文文本?

3 个答案:

答案 0 :(得分:3)

您可以使用Regex.Matches

var matches = Regex.Matches(input_string, regex);
foreach (var m in matches)
{
    // do whatever
}

或者,你可以获得一场比赛,然后获得下一场比赛等等:

var m = Regex.Match(input_string, regex);
while (m.Success)
{
    // do something with this match
    // then get the next match
    m = m.NextMatch();
}

答案 1 :(得分:2)

首先,我建议您将正则表达式更改为:

(?s)~~~ START ([^~]*).*?END \1 ~~~
  1. 在开场时和START之后,([^~]*)会抓住该块的标题。这样可以确保我们可以确保END稍后匹配。
  2. 懒惰.*?最多匹配......
  3. 标题(由\反向引用)和关闭波浪号。
  4. 示例代码

    这是一个完整的程序,您可以使用它进行测试。我没试过。你需要在那里粘贴字符串。

    using System;
    using System.Text.RegularExpressions;
    using System.Collections.Specialized;
    class Program {
    static void Main()    {
    string s1 = @"PASTE YOUR STRING HERE";
    var myRegex = new Regex(@"(?s)~~~ START ([^~]*).*?END \1 ~~~");
    MatchCollection AllMatches = myRegex.Matches(s1);
    Console.WriteLine("\n" + "*** Matches ***");
    if (AllMatches.Count > 0)    {
        foreach (Match SomeMatch in AllMatches)    {
            Console.WriteLine("Title: " + SomeMatch.Groups[1].Value);
            Console.WriteLine("Overall Match: " + SomeMatch.Value);
        }
    }
    
    Console.WriteLine("\nPress Any Key to Exit.");
    Console.ReadKey();
    
    } // END Main
    } // END Program
    

答案 2 :(得分:1)

你需要在一个循环中多次调用正则表达式匹配器,直到没有匹配。考虑修改表达式以避免回溯 - 在您的情况下,这是非常可能的,因为.+是贪婪的(而不是“不情愿”)。

这是一个如何做到的小演示:

var regex = new Regex("~~~ START ([^~]+)~~~([^~]*)~~~ END ([^~]+)~~~", RegexOptions.Multiline);
var m = regex.Match(Data);
while (m.Success) {
    Console.WriteLine("------ Start: {0} --------", m.Groups[1]);
    Console.WriteLine(m.Groups[2]);
    Console.WriteLine("------ End: {0} --------", m.Groups[3]);
    m = m.NextMatch();
}

This example running on ideone.

请注意上述更改 - 我将.替换为[^~]以匹配第一个波浪形,并且还捕获了用于打印的开始和结束标记的内容。