2013-10-22 52 views
0

我有一个完美的正则表达式。正则表达式:在多个捕获中捕获多个

^SENT KV(?<singlelinedata> L(?<line>[1-9]\d*) (?<measureline>\d+)(?: (?<samplingpoint>\d+))+)+$ 

我输入的字符串看起来是这样的:

SENT KV L1 123 1 2 3 L2 456 4 5 6 

唯一的问题是:如何获得小组“samplingpoint”的所有捕获的背景下​​?

该组包含6个捕获,但我也需要上下文信息。第一次捕获“单线数据”组时有三次捕获,第二次捕获时有三次捕获。如何获取这些信息?

组的捕获不包含包含所有包含组的捕获的属性。

我知道我可以编写一个正则表达式来匹配整个字符串,并执行第二个正则表达式来解析所有“单线数据” - 俘获。

我正在寻找一种方式,与指定的正则表达式。

希望有人能帮助我。

回答

0
void Main() 
{ 
    string data = @"SENT KV L1 123 1 2 3 L2 456 4 5 6"; 
    Parse(data).Dump(); 
} 

public class Result 
{ 
    public int Line; 
    public int MeasureLine; 
    public List<int> SamplingPoints; 
} 

private Regex pattern = new Regex(@"^SENT KV(?<singlelinedata> L(?<line>[1-9]\d*) (?<measureline>\d+)(?: (?<samplingpoint>\d+))+)+$", RegexOptions.Multiline); 

public IEnumerable<Result> Parse(string data) 
{ 
    foreach (Match m in pattern.Matches(data)) 
    { 
     foreach (Capture c1 in m.Groups["singlelinedata"].Captures) 
     { 
      int lineStart = c1.Index; 
      int lineEnd = c1.Index + c1.Length; 

      var result = new Result(); 
      result.Line = int.Parse(m.Groups["line"].CapturesWithin(c1).First().Value); 
      result.MeasureLine = int.Parse(m.Groups["measureline"].CapturesWithin(c1).First().Value); 

      result.SamplingPoints = new List<int>(); 
      foreach (Capture c2 in m.Groups["samplingpoint"].CapturesWithin(c1)) 
      { 
       result.SamplingPoints.Add(int.Parse(c2.Value)); 
      } 

      yield return result; 
     } 
    } 
} 

public static class RegexExtensions 
{ 
    public static IEnumerable<Capture> CapturesWithin(this Group group, Capture capture) 
    { 
     foreach (Capture c in group.Captures) 
     { 
      if (c.Index < capture.Index) continue; 
      if (c.Index >= capture.Index + capture.Length) break; 

      yield return c; 
     } 
    } 
} 

编辑:改写为上Group扩展方法。

+0

这是个好主意。我认为这就是_Eli Arbel_的意思是“...使用字符索引来自己计算“,但是在他的回答中,我并没有正确理解它,它看起来可以为组编写一个扩展方法,根据您的GetCaptures实现在其他捕获中获取所有捕获。 –

0

在正则表达式API中没有“子组”的概念。一个组可以有多个捕获,但是你不知道哪个samplingpoint属于哪个line

你唯一的选择是使用字符索引来自己计算它。

+0

如果是这样,我会采取两种正则表达式的唯一选择。第一个匹配整个字符串,第二个匹配“singlelinedata”。 Thx为您的答案。 –

+0

您也可以捕获单个组中的所有数字,然后使用'String.Split'。 –

0

一种不做大量索引匹配并保持单个正则表达式的方法是将捕获组更改为全部具有相同的名称。嵌套捕捉真正得到推到第一,所以你最终得到一个这样的数组堆栈:

["1", "123", "1", "2", "3", "L1 123 1 2 3", "2", "456", "4", "5", "6", "L2 456 4 5 6"]

然后,它只是一个部分LINQ疯狂的事当含有L-捕捉到的结果分成组被找到,然后从每个组中提取数据。

var regex = new Regex(@"^SENT KV(?<singlelinedata> L(?<singlelinedata>[1-9]\d*) (?<singlelinedata>\d+)(?: (?<singlelinedata>\d+))+)+$"); 
var matches = regex.Matches("SENT KV L1 123 1 2 3 L2 456 4 5 6 12 13 L3 789 7 8 9 10"); 
var singlelinedata = matches[0].Groups["singlelinedata"]; 

string groupKey = null; 
var result = singlelinedata.Captures.OfType<Capture>() 
    .Reverse() 
    .GroupBy(key => groupKey = key.Value.Contains("L") ? key.Value : groupKey, value => value.Value) 
    .Reverse() 
    .Select(group => new { key = group.Key, data = group.Skip(1).Reverse().ToList() }) 
    .Select(item => new { line = item.data.First(), measureline = item.data.Skip(1).First(), samplingpoints = item.data.Skip(2).ToList() }) 
    .ToList(); 
0

基于马库斯Jarderot的答案我写了群体的扩展方法,它捕获并返回指定的捕捉范围内的组的全攻略。

扩展方法是这样的:这种方法的

public static IEnumerable<Capture> CapturesWithin(this Group source, Capture captureContainingGroup) 
    { 
     var lowerIndex = captureContainingGroup.Index; 
     var upperIndex = lowerIndex + captureContainingGroup.Length - 1; 

     foreach (var capture in source.Captures.Cast<Capture>()) 
     { 
      if (capture.Index < lowerIndex) 
      { 
       continue; 
      } 

      if (capture.Index > upperIndex) 
      { 
       break; 
      } 

      yield return capture; 
     } 
    } 

用法:

foreach (var capture in match.Groups["singlelinedata"].Captures.Cast<Capture>()) 
{ 
    var samplingpoints = match.Groups["samplingpoint"].CapturesWithin(capture).ToList(); 
    ... 
相关问题