Ersetzen Sie nur einige Gruppen durch Regex

190

Nehmen wir an, ich habe den folgenden regulären Ausdruck:

-(\d+)-

und ich möchte mit C # die Gruppe 1 (\d+)durch ersetzen, um Folgendes AAzu erhalten:

-AA-

Jetzt ersetze ich es mit:

var text = "example-123-example";
var pattern = @"-(\d+)-";
var replaced = Regex.Replace(text, pattern, "-AA-"); 

Aber das gefällt mir nicht wirklich, denn wenn ich _(\d+)_stattdessen das Muster so ändere, dass es übereinstimmt , muss ich auch die Ersatzzeichenfolge um ändern _AA_, was gegen das DRY-Prinzip verstößt.

Ich suche so etwas wie:

Behalten Sie den übereinstimmenden Text genau bei, aber ändern Sie Gruppe 1 nach this textund Gruppe 2 nach another text...

Edit:
Das war nur ein Beispiel. Ich suche nur nach einer generischen Methode, um das zu tun, was ich oben gesagt habe.

Es sollte funktionieren für:

anything(\d+)more_text und jedes Muster, das Sie sich vorstellen können.

Ich möchte nur Gruppen ersetzen und den Rest des Spiels behalten.

Oscar Mederos
quelle

Antworten:

306

Eine gute Idee könnte sein, alles in Gruppen zusammenzufassen, unabhängig davon, ob sie identifiziert werden müssen oder nicht. Auf diese Weise können Sie sie in Ihrer Ersatzzeichenfolge verwenden. Beispielsweise:

var pattern = @"(-)(\d+)(-)";
var replaced = Regex.Replace(text, pattern, "$1AA$3"); 

oder mit einem MatchEvaluator:

var replaced = Regex.Replace(text, pattern, m => m.Groups[1].Value + "AA" + m.Groups[3].Value);

Ein anderer, etwas chaotischer Weg könnte die Verwendung eines Lookbehind / Lookahead sein:

(?<=-)(\d+)(?=-)

bluepnume
quelle
17
Ich habe Ihre Antwort bearbeitet, um weitere Informationen bereitzustellen, aber was Sie gesagt haben, ist völlig richtig. Ich weiß nicht, wie ich es vermisst habe, dass ich alles in Gruppen einteilen konnte, egal ob ich sie verwenden werde oder nicht :) . Meiner Meinung nach ist diese Lösung viel besser und sauberer als die Verwendung von Lookahead und Lookbehinds.
Oscar Mederos
kleiner Tippfehler, Ihr Ersatzmuster sollte $ 1AA $ 3 sein
Myster
1
Damit dies funktioniert, musste ich .Valuezu m.Groups[1]etc. hinzufügen
jbeldock
10
Ebenfalls erwähnenswert - wenn Ihr Ersatztext mit einer Zahl beginnt, funktioniert die erste Lösung ("$ 1AA $ 3") nicht wie beabsichtigt!
Bertie
2
@OscarMederos Sie können auch nicht erfassende Gruppen verwenden - gut für Gruppen, die Sie nicht verwenden. In (?:foo)(bar), $1ersetzen wird bar. Weitere Details
Patrick
34

Sie können dies mit lookahead und lookbehind tun :

var pattern = @"(?<=-)\d+(?=-)";
var replaced = Regex.Replace(text, pattern, "AA"); 
LukeH
quelle
19

Ich brauchte das auch und habe die folgende Erweiterungsmethode dafür erstellt:

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

Verwendung:

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

Ergebnis:

[assembly: AssemblyFileVersion("1.2.3")][assembly: AssemblyFileVersion("1.2.3")]
Daniel Hilgarth
quelle
13

Wenn Sie Ihr Muster nicht ändern möchten, können Sie die Eigenschaften Gruppenindex und Länge einer übereinstimmenden Gruppe verwenden.

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;
Dick Verweij
quelle
Bitte beachten Sie, dass dies nur für das erste Auftreten des Spiels vorausgesetzt wird und funktioniert.
Bartosz
5

Hier ist eine weitere schöne saubere Option, bei der Sie Ihr Muster nicht ändern müssen.

        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));
        });
lockiges Haargenie
quelle
0

Gehen Sie die folgende Codierung durch, um den separaten Gruppenersatz zu erhalten.

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);
BalaS
quelle