计数正则表达式替换(C#)

问题描述:

有没有一种方法可以计算Regex.Replace调用产生的替换次数?计数正则表达式替换(C#)

E.g.对于Regex.Replace("aaa", "a", "b");我想得到数字3(结果是"bbb");对于Regex.Replace("aaa", "(?<test>aa?)", "${test}b");我想获得数字2(结果是"aabab")。

方法,我能想到这样做:

  1. 使用一个递增捕获变量MatchEvaluator,做更换手动
  2. 得到一个MatchCollection和重复它,如果用手工更换,并保持一个计数
  3. 搜索第一,并获得MatchCollection,得到了计数,然后做一个单独更换

方法1和2需要$手工解析取代方法3需要正则表达式匹配字符串两次。有没有更好的办法。

+0

这是一个简单的命令行工具,可以用任何正则表达式搜索调用,并将模式替换为命令行参数。因此理想的情况是需要一种通用的解决方案,不要提前知道该模式。真的,这是为了兴趣 - 在.Net中做这件事的最好方法是什么?看起来像手动分析$替换的MatchEvaluator方法是前进的方向,但它有点凌乱:( – 2011-02-14 16:50:42

+0

西蒙,看我的编辑。 – Chev 2011-02-14 16:56:36

感谢Chevex和Guffa。我开始寻找更好的方法来获得结果,并发现在Match类中有一个用于替换的Result方法。这是拼图的缺失部分。下面的实施例的代码:

using System.Text.RegularExpressions; 

namespace regexrep 
{ 
    class Program 
    { 
     static int Main(string[] args) 
     { 
      string fileText = System.IO.File.ReadAllText(args[0]); 
      int matchCount = 0; 
      string newText = Regex.Replace(fileText, args[1], 
       (match) => 
       { 
        matchCount++; 
        return match.Result(args[2]); 
       }); 
      System.IO.File.WriteAllText(args[0], newText); 
      return matchCount; 
     } 
    } 
} 

与含文件test.txt AAA,命令行regexrep test.txt "(?<test>aa?)" ${test}b将设置%ERRORLEVEL%至2,并切换到aabab的文本。

这应该做到这一点。

 int count = 0; 
    string text = Regex.Replace(text, 
      @"(((http|ftp|https):\/\/|www\.)[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?)", //Example expression. This one captures URLs. 
      match => 
      { 
       string replacementValue = String.Format("<a href='{0}'>{0}</a>", match.Value); 
       count++; 
       return replacementValue; 
      }); 

我不是我开发的计算机上,所以我不能现在就做,但我将稍后进行试验,看看是否有一种方法与lambda表达式要做到这一点,而不是声明方法IncrementCount()仅用于增加一个int。

EDIT修改为使用lambda表达式而不是声明另一个方法。

EDIT2如果您事先不知道该模式,您仍然可以获取匹配对象中的所有分组(您引用的$组),因为它们包含在GroupCollection中。像这样:

 int count = 0; 
    string text = Regex.Replace(text, 
      @"(((http|ftp|https):\/\/|www\.)[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?)", //Example expression. This one captures URLs. 
      match => 
      { 
       string replacementValue = String.Format("<a href='{0}'>{0}</a>", match.Value); 
       count++; 
       foreach (Group g in match.Groups) 
       { 
        g.Value; //Do stuff with g.Value 
       } 
       return replacementValue; 
      }); 
+0

这将工作(谢谢!),但基本上我的方法1。为了使它适用于通用输入和输出,你需要解析替换中的$ {test},所以我们需要更复杂的东西(我指的是“手动解析$替换”)。 – 2011-02-14 16:48:24

+0

匹配对象包含$ groups作为附加到它们的GroupCollection。如果您事先不知道表达式,并且不知道将包括多少个组,那么像我的EDIT2一样循环访问组合集合。我没有在答案中对团队价值做任何事情,但应该很容易让你看到你的成就。 – Chev 2011-02-14 17:04:10

您可以使用,对于每次更换运行MatchEvaluator,这样你可以指望有多少次它发生:

int cnt = 0; 
string result = Regex.Replace("aaa", "a", m => { 
    cnt++; 
    return "b"; 
}); 

第二种情况是棘手的,你必须产生相同的结果作为替换模式会:

int cnt = 0; 
string result = Regex.Replace("aaa", "(?<test>aa?)", m => { 
    cnt++; 
    return m.Groups["test"] + "b"; 
});