代码之家  ›  专栏  ›  技术社区  ›  willeM_ Van Onsem

C语言中的迭代正则表达式捕获#

  •  4
  • willeM_ Van Onsem  · 技术社区  · 14 年前

    我必须读一个包含许多坐标的文件。文件的结构如下:

    X1/Y1,X2/Y2,X3/Y3,X4/Y4
    

    其中x和y是正整数。为了解决这个问题,我想使用一个regex(我认为这通常是一个好主意,因为当模式改变时重构最少)。

    因此,我开发了以下regex:

    Regex r = new Regex(@^(?<Coor>(?<X>[0-9]+)/(?<Y>[0-9]+))(,(?<Coor>(?<X>[0-9]+)/(?<Y>[0-9]+)))*$");
    

    但是,当我在数据上测试这个regex时,例如:

    1302/1425,1917/2010
    

    regex似乎只调用最后一个x、y和coor组。在这种情况下,coor是“12/17”,x是“1917”,y是“2010”。有没有生成某种树的方法?所以我找到了一个对象,它给了我所有的坐标表达式,在每个坐标下有一个x和y分量?

    如果可能的话,我只想使用一个regex,因为格式可能会更改为另一个。

    4 回复  |  直到 10 年前
        1
  •  5
  •   Mark Byers    14 年前

    通过使用 string.Split int.Parse :

    var coords = s.Split(',')
        .Select(x => x.Split('/'))
        .Select(a => new {
            X = int.Parse(a[0]),
            Y = int.Parse(a[1])
        });
    

    如果要使用正则表达式 验证 你可以这样做的字符串:

    "^(?!,)(?:(?:^|,)[0-9]+/[0-9]+)*$"
    

    如果您还想使用基于正则表达式的方法 提取数据 您可以首先使用上面的正则表达式验证字符串,然后按照以下方式额外添加数据:

    var coords = Regex.Matches(s, "([0-9]+)/([0-9]+)")
        .Cast<Match>()
        .Select(match => new
        {
            X = int.Parse(match.Groups[1].Value),
            Y = int.Parse(match.Groups[2].Value)
        });
    

    如果您真的希望使用单个正则表达式同时执行验证和数据提取,可以使用两个捕获组,并在 Captures 每个组的属性。以下是使用单个正则表达式执行验证和数据提取的一种方法:

    List<Group> groups =
        Regex.Matches(s, "^(?!,)(?:(?:^|,)([0-9]+)/([0-9]+))*$")
             .Cast<Match>().First()
             .Groups.Cast<Group>().Skip(1)
             .ToList();
    
    var coords = Enumerable.Range(0, groups[0].Captures.Count)
        .Select(i => new
        {
            X = int.Parse(groups[0].Captures[i]),
            Y = int.Parse(groups[1].Captures[i])
        });
    

    但是,与 字符串 基于解决方案。

        2
  •  3
  •   Guffa    14 年前

    对于这种简单的格式,没有理由使用正则表达式。

    只需拆分字符串并使用普通字符串操作获取坐标:

    var coordinates =
      fileContent.Split(',').Select(s => {
        int pos = s.IndexOf("/");
        return new {
          X = s.Substring(0, pos),
          Y = s.Substring(pos + 1)
        };
      });
    

    如果文件格式变得更加复杂,可以使用正则表达式将其重构为。在此之前,这样的简单代码更容易维护。

        3
  •  2
  •   Brent Arias    14 年前

    如果使用“matches”而不是“match”命令,可能会得到所需的。另外,难道你不能把regex缩短到:

    Regex(@"((?<Coor>(?<X>[0-9]+)/(?<Y>[0-9]+))|,)*");
    
        4
  •  1
  •   CodingGorilla    14 年前

    我认为你的第一个问题是你的正则表达式有缺陷,锚正在抛出匹配。这是我想到的:(这里只显示regex,没有代码)

    (?<Coor>(?<X>[0-9]+)/(?<Y>[0-9]+))

    一个mystagogue也可以工作,但会在逗号上产生“空白”匹配(对我而言)。