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