【问题标题】:Capturing groups, Many groups per line捕获组,每行许多组
【发布时间】:2013-06-07 00:44:01
【问题描述】:

我有一些带有“控制序列”的 html,我已经从内容中删除了 html 标签,现在我想将“控制序列”变成“样式”。

删除 html 标签后,我有了这个...

"<!C43!><!TG!>Some Characters"

最终产生这个...

<span class="C43 TG">Some Characters</span>

到目前为止,我的错误 c# :

Regex reg = new Regex("<!([^<>]+?)!>");

Match matches = reg.Match(line);
foreach (Group group in matches.Groups)
{
    // finds both groups,
    // and remove the control sequence
}

我的“foreach”中还没有太多内容,因为当我使用断点检查它时,它错误地返回了以下组......

Group 1 : <!C43!>
Group 2 : C43
<it does not find second group :( >

任何帮助将不胜感激,但我主要是在寻找正确的正则表达式以在字符串中找到我要查找的内容,但我对正则表达式库也无用,所以最有效的“查找组” ,商店组,从我正在搜索的字符串中删除组'也将不胜感激。

【问题讨论】:

    标签: c# regex


    【解决方案1】:

    你循环错了。试试这个:

    string line = ...;
    Regex reg = ...;
    for (var match = reg.Match(line); match.Success; match = match.NextMatch())
    {
        // in here, don't bother with .Groups... you don't need it
    }
    

    【讨论】:

      【解决方案2】:

      正如其他人所说,您想要循环 Matches 而不是 Groups,因为您的模式只有一组。执行此操作的常用方法是 Michael Gunter 的 for 循环或简单的

      Match m = reg.Match(line);
      while(m.Success)
      {
          // read class from m.Groups[1]
          m = m.NextMatch();
      }
      

      但是,为了解决您的最终问题,单独取出所有数据并将字符串重新组合在一起可能有点烦人 - 特别是如果您想一次在多行中进行此替换。

      因此,您可能需要查看Regex.Replace(接受回调的版本)。这样,您可以在一次匹配中匹配所有内容,然后利用 .NET 的独特功能来访问单个组的多个捕获。

      var line = "<!C43!><!TG!>Some Characters";
      
      MatchEvaluator evaluator = new MatchEvaluator(ReplaceCallback);
      
      string output = Regex.Replace(
          line,
          @"(?:<!([^<>]+)!>)+(.+)",
          evaluator
      );
      

      在你班上的其他地方:

      static string ReplaceCallback(Match match)
      {
          var sb = new StringBuilder("<span class=\"");
          sb.Append(match.Groups[1].Captures[0].Value);
          for(int i = 1; i < match.Groups[1].Captures.Count; i++)
          {
              sb.Append(" ");
              sb.Append(match.Groups[1].Captures[i].Value);
          }
          sb.Append("\">");
          sb.Append(match.Groups[2].Value);
          sb.Append("</span>");
          return sb.ToString();
      }
      

      使用String.Format 设置字符串可能更容易,但我目前找不到String.JoinCaptureCollection 的方法。

      那么这基本上是在做什么:

      模式@"(?:&lt;!([^&lt;&gt;]+)!&gt;)+(.+)" 匹配一个或多个&lt;!...!&gt;“令牌”,然后匹配该行的其余部分。这样做时,它会捕获&lt;!...!&gt; 的内容。每次重复时都会记录另一个捕获,您可以稍后在回调中访问它们。在&lt;!...!&gt; 标记之后,我们使用(.+) 匹配并捕获该行的其余部分。请注意字符串前面的@:它逐字生成字符串,在指定正则表达式模式时应该始终这样做 - 否则在转义时会遇到问题。还要注意第一个左括号后面的?:。这是为了抑制捕获,因为我们不需要另一个包含分隔符 &lt;!!&gt; 的捕获。除非您确实需要捕获,否则始终使用非捕获组也是很好的做法。

      然后,回调函数会为输入中的每个匹配项调用。只有一个匹配包含整行。这场比赛在1 组中捕获了两个标记,在2 组中捕获了其余的标记。

      所以我们现在可以简单地构建一个字符串,它以&lt;span =" 开头,然后是组1 的所有捕获的空格分隔列表,然后是"&gt;,然后是捕获的其余行,最后是结束&lt;/span&gt;.

      如我所说,如果你找到String.Join集合组的方法,回调函数会减少到三行左右。

      如果MatchGroupCapture之间的区别对你来说还是有点模糊,我建议在回调函数中设置一个断点,然后只检查那里的match对象。

      【讨论】:

      • 哇,完美的答案,您的代码就像一种享受!谢谢你! :-)
      【解决方案3】:

      我无法在 RegexHero 中重现您的问题:

      http://www.regexhero.net/tester

      它将 2 个组捕获为:

      1: C43
      1: TG
      

      您确定您的输入是您所期望的吗?您是否正在迭代预期的结果集合?

      【讨论】:

      • 哦...现在您的链接要求安装silverlight...我会检查一下
      • 我会说这与您的代码有关。调试 reg.Match 响应并检查属性等。
      猜你喜欢
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多