2013-10-22 9 views
0

완벽하게 작동하는 정규 표현식을 사용했습니다.Regex : 다중 캡처에서 다중 캡처

^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 캡처를 포함하지만 너무 컨텍스트 정보를 필요로한다. 그룹 "singlelinedata"의 첫 번째 캡처에는 세 가지 캡처가 있고 두 번째 캡처에는 세 가지 캡처가 있습니다. 이 정보를 얻는 방법?

그룹의 캡처가 포함 된 그룹을 모두 캡처를 포함하는 속성을 포함하지 않습니다.

는 나는 전체 문자열과 일치하는 모든 "singlelinedata"-captures을 구문 분석하는 두 번째 정규 표현식을 수행하는 하나의 정규 표현식을 쓸 수 있다는 것을 알고있다.

나는 지정된 정규식 작동하는 방법을 찾고 있어요.

누군가 나를 도울 수 있기를 바랍니다.

답변

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

이것은 좋은 생각입니다. 그게 엘리 알벨이 의미하는 것 "이라고 생각합니다."문자 색인을 사용하여 직접 계산할 수 있지만 그 대답은 올바르게 이해하지 못했습니다. GetCaptures 구현에 따라 다른 캡처 내에서 모든 캡처를 가져 오는 그룹에 대해 확장 메서드를 작성할 수 있습니다. –

0

는 정규식 API에서 "하위 그룹"의 개념이 없습니다. 그룹에는 여러 개의 캡처가있을 수 있지만 어느 것이 에 속하는지 samplingpoint에 속하는지 알 수 없습니다.

당신은 문자 색인을 사용하여 직접 계산할 수 있습니다.

+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"]

그런 다음이 캡처는 L을 포함 할 때 그룹으로 결과를 분할하는 몇 가지 LINQ의 막무가내의 문제를의 : 중첩 된 캡처 실제로이 같은 배열로 끝날 첫째 ​​있도록 스택으로 푸시 얻을 이 발견되면 각 그룹에서 데이터를 꺼냅니다. 마르쿠스 Jarderot의 답변에 따라

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

나는 캡처를 받아 지정된 캡처 내에서 해당 그룹의 모든 캡처를 반환 그룹에 대한 확장 방법을 썼다.

확장 방법은 다음과 같습니다 :이 방법의

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(); 
    ...