Ganti hanya beberapa grup dengan Regex

191

Misalkan saya memiliki regex berikut:

-(\d+)-

dan saya ingin mengganti, menggunakan C #, Grup 1 (\d+)dengan AA, untuk mendapatkan:

-AA-

Sekarang saya menggantinya menggunakan:

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

Tapi saya tidak terlalu suka ini, karena jika saya mengubah pola untuk mencocokkan _(\d+)_sebagai gantinya, saya harus mengganti string pengganti _AA_juga, dan ini bertentangan dengan prinsip KERING.

Saya mencari sesuatu seperti:

Pertahankan teks yang cocok persis seperti apa adanya, tetapi ubah Grup 1 dengan this textdan Grup 2 dengan another text...

Sunting:
Itu hanya contoh. Saya hanya mencari cara umum untuk melakukan apa yang saya katakan di atas.

Ini harus bekerja untuk:

anything(\d+)more_text dan pola apa pun yang dapat Anda bayangkan.

Yang ingin saya lakukan adalah mengganti hanya grup, dan mempertahankan sisa pertandingan.

Oscar Mederos
sumber

Jawaban:

307

Ide yang bagus adalah merangkum semua yang ada di dalam kelompok, tidak peduli apakah perlu mengidentifikasi mereka atau tidak. Dengan begitu Anda bisa menggunakannya dalam string pengganti Anda. Sebagai contoh:

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

atau menggunakan MatchEvaluator:

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

Cara lain, sedikit berantakan, bisa menggunakan lookbehind / lookahead:

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

bluepnume
sumber
17
Saya mengedit jawaban Anda untuk memberikan lebih banyak informasi, tetapi apa yang Anda katakan sepenuhnya benar. Tidak tahu bagaimana saya merindukan bahwa saya bisa memasukkan semuanya ke dalam kelompok, tidak peduli apakah akan menggunakannya atau tidak :) . Menurut pendapat saya, solusi itu jauh lebih baik dan lebih bersih daripada menggunakan lookahead dan lookbehinds.
Oscar Mederos
kesalahan ketik kecil, pola penggantian Anda harus $ 1AA $ 3
Myster
1
Agar ini berfungsi, saya harus menambahkan .Valueke m.Groups[1]dll.
jbeldock
11
Juga patut dicatat - jika teks pengganti Anda dimulai dengan angka, solusi pertama ("$ 1AA $ 3") tidak akan berfungsi sebagaimana mestinya!
Bertie
2
@OscarMederos Anda juga dapat menggunakan grup yang tidak menangkap - bagus untuk grup yang tidak Anda gunakan. Dalam (?:foo)(bar), $1akan diganti bar. lebih detail
Patrick
34

Anda dapat melakukan ini menggunakan lookahead dan lookbehind :

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

Saya juga membutuhkan ini dan saya membuat metode ekstensi berikut untuk itu:

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

Pemakaian:

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

Hasil:

[assembly: AssemblyFileVersion("1.2.3")][assembly: AssemblyFileVersion("1.2.3")]
Daniel Hilgarth
sumber
Saya suka implementasi ini tetapi tidak menggantikan beberapa pertandingan. Saya memposting versi yang tidak
Vladimir
13

Jika Anda tidak ingin mengubah pola, Anda dapat menggunakan properti Indeks Grup dan Panjang grup yang cocok.

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
sumber
Harap dicatat bahwa ini mengasumsikan dan hanya akan berfungsi untuk kemunculan pertama pertandingan.
Bartosz
5

Berikut ini adalah opsi bersih lain yang bagus yang tidak perlu mengubah pola Anda.

        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));
        });
curlyhairedgenius
sumber
0

buka kode di bawah ini untuk mendapatkan penggantian kelompok yang terpisah.

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);
Bala
sumber
0

Ini adalah versi yang mirip dengan Daniel tetapi mengganti beberapa kecocokan:

public static string ReplaceGroup(string input, string pattern, RegexOptions options, string groupName, string replacement)
{
    Match match;
    while ((match = Regex.Match(input, pattern, options)).Success)
    {
        var group = match.Groups[groupName];

        var sb = new StringBuilder();

        // Anything before the match
        if (match.Index > 0)
            sb.Append(input.Substring(0, match.Index));

        // The match itself
        var startIndex = group.Index - match.Index;
        var length = group.Length;
        var original = match.Value;
        var prior = original.Substring(0, startIndex);
        var trailing = original.Substring(startIndex + length);
        sb.Append(prior);
        sb.Append(replacement);
        sb.Append(trailing);

        // Anything after the match
        if (match.Index + match.Length < input.Length)
            sb.Append(input.Substring(match.Index + match.Length));

        input = sb.ToString();
    }

    return input;
Vladimir
sumber