C# 正则表达式:多个捕获中的多个捕获

C# 正则表达式:多个捕获中的多个捕获,c#,regex,C#,Regex,我有一个完美的正则表达式 ^SENT KV(?<singlelinedata> L(?<line>[1-9]\d*) (?<measureline>\d+)(?: (?<samplingpoint>\d+))+)+$ 唯一的问题是:如何获取组“samplingpoint”的所有捕获的上下文 此组包含6个捕获,但我也需要上下文信息。组“singlelinedata”的第一个捕获中有三个捕获,第二个捕获中有三个捕获。如何获取这些信息 组的捕获不包含包

我有一个完美的正则表达式

^SENT KV(?<singlelinedata> L(?<line>[1-9]\d*) (?<measureline>\d+)(?: (?<samplingpoint>\d+))+)+$
唯一的问题是:如何获取组“samplingpoint”的所有捕获的上下文

此组包含6个捕获,但我也需要上下文信息。组“singlelinedata”的第一个捕获中有三个捕获,第二个捕获中有三个捕获。如何获取这些信息

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

我知道我可以编写一个正则表达式来匹配整个字符串,并执行第二个正则表达式来解析所有“singlelinedata”捕获

我正在寻找一种使用指定正则表达式的方法

希望有人能帮助我。

正则表达式API中没有“子组”的概念。一个组可以有多个捕获,但您无法知道哪个
采样点
属于哪个

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

void Main()
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;
        }
    }
}
{ 串数据=@“已发送KV L1 123 1 2 3 L2 456 4 5 6”; Parse(data.Dump(); } 公开课成绩 { 公共内线; 公共测量线; 公共列表采样点; } 私有正则表达式模式=新正则表达式(@“^KV(?L(?[1-9]\d*)(?\d+(?\d+)+)+$”,RegexOptions.Multiline); 公共IEnumerable解析(字符串数据) { foreach(匹配模式中的m.Matches(数据)) { foreach(捕获m.Groups[“singlelinedata”]中的c1。捕获) { int lineStart=c1.索引; int lineEnd=c1.索引+c1.长度; var 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=新列表(); foreach(捕获m.Groups[“采样点”]中的c2.CapturesWithin(c1)) { result.SamplingPoints.Add(int.Parse(c2.Value)); } 收益结果; } } } 公共静态类RegexExtensions { 公共静态IEnumerable CapturesWithin(此组,Capture Capture) { foreach(捕获组中的c.Captures) { 如果(c.Index=capture.Index+capture.Length)中断; 收益率c; } } }

编辑:
上作为扩展方法重写

一种不进行大量索引匹配并保留单个正则表达式的方法是将捕获组更改为所有具有相同名称。嵌套捕获实际上首先被推送到堆栈上,因此最终得到如下数组:

SENT KV L1 123 1 2 3 L2 456 4 5 6
    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;
        }
    }
[“1”、“123”、“1”、“2”、“3”、“L1 123 1 2 3”、“2”、“456”、“4”、“5”、“6”、“L2 456 4 6”]

然后,当发现一个包含L的捕获时,将结果分成若干组,然后从每个组中取出数据,这只是LINQ疯狂的问题

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();
var regex=new regex(@“^KV(?L(?[1-9]\d*)(?\d+(?\d+)+)+)+$”;
var匹配=正则表达式匹配(“发送KV L1 123 1 2 3 L2 456 4 5 6 12 13 L3 789 8 10”);
var singlelinedata=匹配[0]。组[“singlelinedata”];
字符串groupKey=null;
var result=singlelinedata.Captures.OfType()
.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();
根据Markus Jarderot的回答,我为组编写了一个扩展方法,该方法接受一个捕获并返回指定捕获内该组的所有捕获

扩展方法如下所示:

SENT KV L1 123 1 2 3 L2 456 4 5 6
    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;
        }
    }
public static IEnumerable CapturesWithin(此组源,Capture captureContainingGroup)
{
var lowerIndex=captureContainingGroup.Index;
var upperIndex=lowerIndex+captureContainingGroup.Length-1;
foreach(source.Captures.Cast()中的变量捕获)
{
如果(capture.IndexupperIndex)
{
打破
}
收益捕获;
}
}
此方法的用法:

foreach (var capture in match.Groups["singlelinedata"].Captures.Cast<Capture>())
{
    var samplingpoints = match.Groups["samplingpoint"].CapturesWithin(capture).ToList();
    ...
foreach(match.Groups[“singlelinedata”].Captures.Cast()中的变量捕获)
{
var samplingpoints=match.Groups[“samplingpoint”].CapturesWithin(capture.ToList();
...

如果这是唯一的选项,我将选择两个正则表达式。第一个正则表达式与整个字符串匹配,第二个正则表达式用于每次捕获“singlelinedata”。Thx作为您的答案。您也可以捕获单个组中的所有数字,然后使用
字符串。拆分
。这是一个好主意。我认为Eli Arbel的意思就是这样“…使用字符索引自己计算”但在他的回答中我没有正确理解。似乎可以为组编写一个扩展方法,根据您对
GetCaptures
的实现,在其他捕获中获取所有捕获。