【问题标题】:Regex and proper capture using .matches .Concat in C#在 C# 中使用 .matches .Concat 进行正则表达式和正确捕获
【发布时间】:2018-11-28 23:56:11
【问题描述】:

我有以下正则表达式:

@"{thing:(?:((\w)\2*)([^}]*?))+}"

我正在使用它在字符串中查找匹配项:

MatchCollection matches = regex.Matches(string);
       IEnumerable formatTokens = matches[0].Groups[3].Captures
                                   .OfType<Capture>()
                                   .Where(i => i.Length > 0)
                                   .Select(i => i.Value)
                                   .Concat(matches[0].Groups[1].Captures.OfType<Capture>().Select(i => i.Value));

这用于产生我想要的结果;然而,我的目标已经改变了。这是现在想要的行为:

假设输入的字符串是'stuff/{thing:aa/bb/cccc}{thing:cccc}'

想要 formatTokens 是:

formatTokens[0] == "aa/bb/cccc"
formatTokens[1] == "cccc"

现在,这就是我得到的:

formatTokens[0] == "/"
formatTokens[1] == "/"
formatTokens[2] == "cccc"
formatTokens[3] == "bb"
formatTokens[4] == "aa"

特别注意“cccc”即使输入了两次也不会出现两次。

我认为问题在于 1) 正则表达式中的重新捕获和 2) concat 配置(这是从我想要将所有内容分开时开始的),但到目前为止我还没有找到能够产生我想要的组合.有人可以阐明正确的正则表达式/连接组合以产生上述预期结果吗?

【问题讨论】:

  • 听起来好像你只想要Regex.Matches(s, @"{thing:([^}]*)}").Cast&lt;Match&gt;().Select(x =&gt; x.Groups[1].Value).ToList() (regex demo)
  • @WiktorStribiżew 这很有效,非常感谢。您想将您的评论作为答案发布,以便我接受它作为答案吗?再次感谢。
  • (?&lt;={thing:).*?(?=}) 怎么样,这不是更好的答案吗?我应该发布它并且您可以接受吗?或者,你是不是有点疯狂地使用特定于重复字母的正则表达式?!?!?

标签: c# regex match regex-group


【解决方案1】:

你可以使用

Regex.Matches(s, @"{thing:([^}]*)}")
    .Cast<Match>()
    .Select(x => x.Groups[1].Value)
    .ToList()

regex demo

详情

  • {thing: - 文字 {thing: 子字符串
  • ([^}]*) - 捕获组 #1(获得匹配后,可以通过 match.Groups[1].Value 访问其值):除 } 之外的 0+ 个字符
  • } - } 字符。

这样,您可以找到多个匹配项,并且只在结果列表/数组中收集第 1 组值。

【讨论】:

    【解决方案2】:

    模组更新

    我不确定您为什么选择 Stringnuts 正则表达式,因为它匹配
    大括号内的任何东西{}

    对 SO 的温顺不会得到深厚知识的满足,
    所以这可能是你真正的问题。

    让我们分析您的正则表达式。

     {thing:
     (?:
          (                             # (1 start)
               ( \w )                        # (2)
               \2* 
          )                             # (1 end)
          ( [^}]*? )                    # (3)
     )+
     }
    

    这减少到这个

     {thing:
     (?: \w [^}]*? )+
     }
    

    唯一的限制是{thing:之后必须有一个单词。
    之后可以有其他任何东西,因为这个子句[^}]*?接受
    任何东西。
    此外,即使该子句不是贪婪的,周围的集群也只会运行一次迭代(?: )+

    因此,基本上,除了单个单词的要求之外,它几乎什么都不做。

    您的正则表达式可用于as is 来获得复杂的匹配,
    并且因为您已经捕获了 Capture Collections 中的所有部分,
    对于每场比赛,您可以使用下面的代码将它们拼凑在一起。

    在您继续其他内容之前,我会尝试更好地理解正则表达式,因为它可能比
    用于提取数据的语言技巧。

    这里是你如何使用你的 unaltered 正则表达式将它们拼凑在一起的方法。

    Regex regex = new Regex(@"{thing:(?:((\w)\2*)([^}]*?))+}");
    string str = "stuff/{thing:aa/bb/cccc}{thing:cccc}";
    foreach (Match match in regex.Matches(str))
    {
        CaptureCollection cc1 = match.Groups[1].Captures;
        CaptureCollection cc3 = match.Groups[3].Captures;
        string token = "";
        for (int i = 0; i < cc1.Count; i++)
            token += cc1[i].Value + cc3[i].Value;
        Console.WriteLine("{0}", token);
    }
    

    输出

    aa/bb/cccc
    cccc
    

    请注意,例如,您的正则表达式几乎可以匹配内部的任何内容
    只要第一个字符是一个单词,就可以使用大括号。

    例如匹配{thing:Z,,,*()(((asgassgasg,asgfasgafg\/\=99.239 }

    您可能需要考虑实际允许的要求
    大括号里面。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-16
      • 1970-01-01
      相关资源
      最近更新 更多