Количество регулярных выражений заменяет (C #) - PullRequest
17 голосов
/ 14 февраля 2011

Есть ли способ подсчитать количество замен, выполняемых вызовом Regex.Replace?

Например, для Regex.Replace("aaa", "a", "b"); Я хочу получить число 3 (результат равен "bbb");для Regex.Replace("aaa", "(?<test>aa?)", "${test}b"); Я хочу получить число 2 (результат - "aabab").

Способы, которые я могу сделать, чтобы это сделать:

  1. Использование MatchEvaluator, который увеличивает захваченныйпеременная, выполняющая замену вручную
  2. Получите MatchCollection и выполните итерацию, выполните замену вручную и сохраните счет
  3. Сначала выполните поиск и получите MatchCollection, получите отсчет, затем выполните отдельный подсчетreplace

Методы 1 и 2 требуют ручного анализа $ replacements, метод 3 требует регулярного выражения, сопоставляющего строку дважды.Есть ли лучший способ.

Ответы [ 3 ]

14 голосов
/ 14 февраля 2011

Спасибо и 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.

7 голосов
/ 14 февраля 2011

Вы можете использовать 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";
});
3 голосов
/ 14 февраля 2011

Это должно сделать это.

     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;
          });

Я не на своем компьютере разработчика, поэтому я не могу сделать это прямо сейчас, но я собираюсь позже поэкспериментировать и посмотреть, есть ли способ сделать это с помощью лямбда-выражений вместо объявления метода IncrementCount ( ) просто увеличить int.

РЕДАКТИРОВАТЬ изменено, чтобы использовать лямбда-выражение вместо объявления другого метода.

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;
          });
...