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

时间:2011-02-14 15:55:59

标签: c# .net regex replace

有没有办法计算Regex.Replace调用的替换次数?

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

我能想到这样做的方式:

  1. 使用MatchEvaluator递增捕获的变量,手动执行替换
  2. 获取MatchCollection并迭代它,手动进行替换并保持计数
  3. 首先搜索并获取MatchCollection,从中获取计数,然后单独执行替换
  4. 方法1和2需要手动解析$替换,方法3需要正则表达式匹配字符串两次。有没有更好的方法。

3 个答案:

答案 0 :(得分:14)

感谢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。

答案 1 :(得分:7)

您可以使用为每次替换运行的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";
});

答案 2 :(得分:3)

这应该这样做。

     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。

修改

编辑以使用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;
          });