正如其他人所说,您想要循环 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.Join 和CaptureCollection 的方法。
那么这基本上是在做什么:
模式@"(?:<!([^<>]+)!>)+(.+)" 匹配一个或多个<!...!>“令牌”,然后匹配该行的其余部分。这样做时,它会捕获<!...!> 的内容。每次重复时都会记录另一个捕获,您可以稍后在回调中访问它们。在<!...!> 标记之后,我们使用(.+) 匹配并捕获该行的其余部分。请注意字符串前面的@:它逐字生成字符串,在指定正则表达式模式时应该始终这样做 - 否则在转义时会遇到问题。还要注意第一个左括号后面的?:。这是为了抑制捕获,因为我们不需要另一个包含分隔符 <! 和 !> 的捕获。除非您确实需要捕获,否则始终使用非捕获组也是很好的做法。
然后,回调函数会为输入中的每个匹配项调用。只有一个匹配包含整行。这场比赛在1 组中捕获了两个标记,在2 组中捕获了其余的标记。
所以我们现在可以简单地构建一个字符串,它以<span =" 开头,然后是组1 的所有捕获的空格分隔列表,然后是">,然后是捕获的其余行,最后是结束</span>.
如我所说,如果你找到String.Join集合组的方法,回调函数会减少到三行左右。
如果Match、Group和Capture之间的区别对你来说还是有点模糊,我建议在回调函数中设置一个断点,然后只检查那里的match对象。