일부 그룹 만 정규식으로 교체


191

다음 정규식이 있다고 가정 해 봅시다.

-(\d+)-

그리고 C #을 사용하여 Group 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...

편집 :
그것은 단지 예일뿐입니다. 나는 위에서 말한 것을 수행하는 일반적인 방법을 찾고 있습니다.

그것은 작동해야합니다 :

anything(\d+)more_text 상상할 수있는 모든 패턴.

내가하고 싶은 것은 그룹 만 교체하고 나머지 경기는 유지하는 것입니다.

답변:


307

그룹을 식별해야하는지 여부에 관계없이 모든 것을 그룹으로 캡슐화하는 것이 좋습니다. 그렇게하면 대체 문자열에 사용할 수 있습니다. 예를 들면 다음과 같습니다.

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+)(?=-)


17
더 많은 정보를 제공하기 위해 답변을 편집했지만 말한 내용은 완전히 맞습니다. 사용 여부에 관계없이 모든 것을 그룹 안에 넣을 수 있다는 점을 모릅니다 :) . 내 생각에, 그 솔루션은 lookahead와 lookbehinds를 사용하는 것보다 훨씬 좋고 깨끗합니다.
Oscar Mederos

작은 오타, 교체 패턴은 $ 1AA $ 3이어야합니다
Myster

1
이 작업을 수행하려면 다음과 같이 추가 .Value해야했습니다 m.Groups[1].
jbeldock

11
또한 대체 텍스트가 숫자로 시작하면 첫 번째 솔루션 ( "$ 1AA $ 3")이 의도 한대로 작동하지 않습니다!
Bertie

2
@OscarMederos는 캡처하지 않은 그룹을 사용할 수도 있습니다. 사용하지 않는 그룹에 좋습니다. 에서가 (?:foo)(bar), $1대체합니다 bar. 자세한 내용
Patrick


19

나는 또한 이것을 필요로했고 그것을 위해 다음 확장 방법을 만들었다.

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

이 구현이 마음에 들지만 여러 개의 일치 항목을 대체하지는 않습니다. 내가 않는 버전 게시
블라디미르

13

패턴을 변경하지 않으려는 경우 일치하는 그룹의 그룹 색인 및 길이 특성을 사용할 수 있습니다.

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;

이것은 첫 번째 경기에서만 가정되고 작동한다는 점에 유의하십시오.
Bartosz

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

0

별도의 그룹 교체를 받으려면 아래 코딩을 수행하십시오.

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

0

다음은 Daniel과 비슷한 버전이지만 여러 개의 일치 항목을 대체합니다.

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;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.