Заменяет регулярное выражение (С#)
Есть ли способ подсчитать количество замен для вызова 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\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)", //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\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)", //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;
});