Замените только некоторые группы с помощью Regex
Предположим, что у меня есть следующее регулярное выражение:
-(\d+)-
и я хочу заменить, используя С#, группу 1 (\d+)
на AA
, чтобы получить:
-AA-
Теперь я заменяю его, используя:
var text = "example-123-example";
var pattern = @"-(\d+)-";
var replaced = Regex.Replace(text, pattern, "-AA-");
Но мне это не очень нравится, потому что если я изменю шаблон для соответствия _(\d+)_
, вместо этого мне придется изменить строку замены на _AA_
, и это противоречит принципу DRY.
Я ищу что-то вроде:
Сохраняйте согласованный текст точно так, как он есть, но измените группу 1 на this text
и группу 2 на another text
...
Edit:
Это был просто пример. Я просто ищу общий способ сделать то, что я сказал выше.
Он должен работать для:
anything(\d+)more_text
и любой шаблон, который вы можете себе представить.
Все, что я хочу сделать, это заменить только группы и сохранить остальную часть соответствия.
Ответы
Ответ 1
Хорошей идеей может быть инкапсуляция всего внутри групп, независимо от необходимости идентифицировать их или нет. Таким образом, вы можете использовать их в своей заменяющей строке. Например:
var pattern = @"(-)(\d+)(-)";
var replaced = Regex.Replace(text, pattern, "$1AA$3");
или используя MatchEvaluator:
var replaced = Regex.Replace(text, pattern, m => m.Groups[1].Value + "AA" + m.Groups[3].Value);
Другой способ, слегка запутанный, может использовать lookbehind/lookahead:
(?<=-)(\d+)(?=-)
Ответ 2
Вы можете сделать это с помощью lookahead и lookbehind:
var pattern = @"(?<=-)\d+(?=-)";
var replaced = Regex.Replace(text, pattern, "AA");
Ответ 3
Если вы не хотите менять свой шаблон, вы можете использовать свойства Group Index и Length для сопоставленной группы.
var text = "example-123-example";
var pattern = @"-(\d+)-";
var regex = new RegEx(pattern);
var match = regex.Match(text);
var firstPart = text.Substring(0,match.Groups[1].Index);
var secondPart = text.Substring(match.Groups[1].Index + match.Groups[1].Length);
var fullReplace = firstPart + "AA" + secondPart;
Ответ 4
Мне также понадобилось это, и я создал для него следующий метод расширения:
public static class RegexExtensions
{
public static string ReplaceGroup(
this Regex regex, string input, string groupName, string replacement)
{
return regex.Replace(
input,
m =>
{
var group = m.Groups[groupName];
var sb = new StringBuilder();
var previousCaptureEnd = 0;
foreach (var capture in group.Captures.Cast<Capture>())
{
var currentCaptureEnd =
capture.Index + capture.Length - m.Index;
var currentCaptureLength =
capture.Index - m.Index - previousCaptureEnd;
sb.Append(
m.Value.Substring(
previousCaptureEnd, currentCaptureLength));
sb.Append(replacement);
previousCaptureEnd = currentCaptureEnd;
}
sb.Append(m.Value.Substring(previousCaptureEnd));
return sb.ToString();
});
}
}
Использование:
var input = @"[assembly: AssemblyFileVersion(""2.0.3.0"")][assembly: AssemblyFileVersion(""2.0.3.0"")]";
var regex = new Regex(@"AssemblyFileVersion\(""(?<version>(\d+\.?){4})""\)");
var result = regex.ReplaceGroup(input , "version", "1.2.3");
Результат:
[assembly: AssemblyFileVersion("1.2.3")][assembly: AssemblyFileVersion("1.2.3")]
Ответ 5
Вот еще одна хорошая чистая опция, которая не требует изменения вашего шаблона.
var text = "example-123-example";
var pattern = @"-(\d+)-";
var replaced = Regex.Replace(text, pattern, (_match) =>
{
Group group = _match.Groups[1];
string replace = "AA";
return String.Format("{0}{1}{2}", _match.Value.Substring(0, group.Index - _match.Index), replace, _match.Value.Substring(group.Index - _match.Index + group.Length));
});
Ответ 6
выполните следующую кодировку, чтобы получить отдельную замену группы.
new_bib = Regex.Replace(new_bib, @"(?s)(\\bibitem\[[^\]]+\]\{" + pat4 + @"\})[\s\n\v]*([\\\{\}a-zA-Z\.\s\,\;\\\#\\\$\\\%\\\&\*\@\\\!\\\^+\-\\\=\\\~\\\:\\\" + dblqt + @"\\\;\\\`\\\']{20,70})", delegate(Match mts)
{
var fg = mts.Groups[0].Value.ToString();
var fs = mts.Groups[1].Value.ToString();
var fss = mts.Groups[2].Value.ToString();
fss = Regex.Replace(fss, @"[\\\{\}\\\#\\\$\\\%\\\&\*\@\\\!\\\^+\-\\\=\\\~\\\:\\\" + dblqt + @"\\\;\\\`\\\']+", "");
return "<augroup>" + fss + "</augroup>" + fs;
}, RegexOptions.IgnoreCase);