C# 替换字符串中的第n个正则表达式匹配项

C# 替换字符串中的第n个正则表达式匹配项,c#,regex,C#,Regex,我知道有很多这样的问题,但我找不到一个能解释他们是如何实施模式以返回第N场比赛的,那场比赛被打破了。我看到的所有答案都只是给OP一个简单解释的代码 我知道的是,您需要在模式中实现这个{X},其中X是您想要返回的数字 因此,我试图在两个字符之间匹配字符串,我似乎已经能够让它工作了 要测试的字符串如下所示 “=StringOne&=StringTwo&=StringThree&=StringFour&” 同样,在尽可能多地阅读之后,这个模式也会返回所有匹配项 [^/=]+(?=&){1}

我知道有很多这样的问题,但我找不到一个能解释他们是如何实施模式以返回第N场比赛的,那场比赛被打破了。我看到的所有答案都只是给OP一个简单解释的代码

我知道的是,您需要在模式中实现这个
{X}
,其中
X
是您想要返回的数字

因此,我试图在两个
字符之间匹配
字符串
,我似乎已经能够让它工作了

要测试的字符串如下所示

“=StringOne&=StringTwo&=StringThree&=StringFour&”

同样,在尽可能多地阅读之后,这个模式也会返回所有匹配项

[^/=]+(?=&){1}
由于
{1}
是默认值,因此在上述模式中是多余的。 但我不能这么做

[^/=]+(?=&){2}
因为它不会像我期待的那样返回第三场比赛


所以,有人能告诉我正确的方向,并解释如何获得所需的模式,以找到所需匹配的发生情况吗?

纯正则表达式方法是可能的,但如果您的模式很复杂,则效率并不高

var s = "=StringOne&=StringTwo&=StringThree&=StringFour&";
var idx = 2;     // Replace this occurrence
var result = Regex.Replace(s, $@"^(=(?:[^=&]+&=){{{idx-1}}})[^=&]+", "${1}REPLACED");
Console.WriteLine(result); // => =StringOne&=REPLACED&=StringThree&=StringFour&
请参阅和

正则表达式详细信息

  • ^
    -字符串的开头
  • (=(?:[^=&]+&=){1}
    -第1组捕获:
    • =
      -一个
      =
      符号
    • (?:[^=&]+&=){1}
      -1次出现(此数字是动态生成的)
    • [^=&]+
      -1个或多个字符,而不是
      =
      &
      注意如果字符串可能包含
      =
      &
      ,则更安全的做法是将其替换为
      *?
      并将
      RegexOptions.Singleline
      选项传递给regex编译器)
    • &=
      -a
      &=
      子字符串
  • [^=&]+
    -1个或多个字符,而不是
    =
    &
替换模式中的
${1}
将组1的内容插入到结果字符串中

作为替代方案,我可以建议在每次匹配时引入一个计数器和增量,并且仅在计数器等于指定的匹配出现次数时替换该计数器

使用

cnt
Regex中的匹配计算器中递增。Replace
m
被分配当前的
match
对象。当
cnt
等于
idx\u to\u replace
时,将发生替换,否则,将粘贴回整个匹配(使用
m.Value

另一种方法是遍历匹配项,一旦找到第n个匹配项,则通过将字符串拆分为匹配前的部分和匹配后的部分来替换它,一旦替换完成,循环就会中断:

var s = "=StringOne&=StringTwo&=StringThree&=StringFour&";
var idx_to_replace = 2;     // Replace this occurrence
var cnt = 0;                // Counter
var result = string.Empty;  // Final result variable
var rx = "[^=]+(?=&)";      // Pattern
for (var m=Regex.Match(s, rx); m.Success; m = m.NextMatch())
{
    cnt++;
    if (cnt == idx_to_replace) {
        result = $"{s.Substring(0, m.Index)}REPLACED{s.Substring(m.Index+m.Length)}";
        break;
    }
}
Console.WriteLine(result); // => =StringOne&=REPLACED&=StringThree&=StringFour&


这可能会更快,因为引擎不必查找所有匹配项。

创建一个将依次匹配每个组的正则表达式,使用接受委托的替换重载,只使用一个计数器。使用url参数解析器如何?@LasseVågsætherKarlsen,我正在研究如何按照您所说的顺序匹配每个组。也许我需要一段时间来看看我是否可以完全通过正则表达式来解决这个问题,正如你可能看到的那样,Witor实际上已经使用C#和正则表达式的组合解决了这个问题。为什么不使用uribuilder内置的querystring解析器呢?非常有趣的方法,我不知道你能做这样的事情+1.在我找到的任何搜索中,我都没有看到有人这样做。非常感谢你的精彩解释,这正是我所希望的。这个答案肯定会在将来帮助别人,而不是我。
var s = "=StringOne&=StringTwo&=StringThree&=StringFour&";
var idx_to_replace = 2; // Replace this occurrence
var cnt = 0;            // Counter
var result = Regex.Replace(s, "[^=]+(?=&)", m => {  // Match evaluator
        cnt++; return cnt == idx_to_replace ? "REPLACED" : m.Value; });
Console.WriteLine(result); 
// => =StringOne&=REPLACED&=StringThree&=StringFour&
var s = "=StringOne&=StringTwo&=StringThree&=StringFour&";
var idx_to_replace = 2;     // Replace this occurrence
var cnt = 0;                // Counter
var result = string.Empty;  // Final result variable
var rx = "[^=]+(?=&)";      // Pattern
for (var m=Regex.Match(s, rx); m.Success; m = m.NextMatch())
{
    cnt++;
    if (cnt == idx_to_replace) {
        result = $"{s.Substring(0, m.Index)}REPLACED{s.Substring(m.Index+m.Length)}";
        break;
    }
}
Console.WriteLine(result); // => =StringOne&=REPLACED&=StringThree&=StringFour&