Заменяет регулярное выражение (С#)

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

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

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

  • Используйте MatchEvaluator, который увеличивает захваченную переменную, выполняя замену вручную
  • Получите MatchCollection и повторите его, выполнив замену вручную и сохранив счет
  • Сначала найдите и получите MatchCollection, получите счетчик, затем выполните отдельную замену

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

Ответы

Ответ 1

Спасибо и Chevex и Guffa. Я начал искать лучший способ получить результаты и обнаружил, что есть метод Result в классе Match, который выполняет подстановку. Это недостающий кусок головоломки. Пример кода ниже:

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.

Ответ 2

Вы можете использовать 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

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

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

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

EDIT изменен, чтобы использовать выражение лямбда вместо объявления другого метода.

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