2013-10-22 105 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(); 
    ... 
相關問題