简体   繁体   中英

Substitute only one group when dealing with an unknown number of capturing groups

Assuming I have this input:

/green/blah/agriculture/apple/blah/

I'm only trying to capture and replace the occurrence of apple (need to replace it with orange), so I have this regex

var regex =  new Regex("^/(?:green|red){1}(?:/.*)+(apple){1}(?:/.*)");

So I'm grouping sections of the input, but as non-capturing, and only capturing the one I'm concerned with. According to this $` will retrieve everything before the match in the input string, and $' will get everything after, so theoretically the following should work:

"$`Orange$'"

But it only retrieves the match ("apple").

Is it possible to do this with just substitutions and NOT match evaluators and looping through groups?

The issue is that apple can occur anywhere in that url scheme, hence an unknown number of capture groups.

Thanks.

To achieve what you want, I slightly changed your regex.

The new regex looks like this look for the updated version at the end of the answer :

What I am doing here is, I want all the other groups to become captured groups. Doing this I can use them as follow:

String replacement = "$1Orange$2";
string result = Regex.Replace(text, regex.ToString(), replacement);

I am using group 1,2 and 4 and in the middle of everything (where I suspect 'apple') I replace it with Orange .

A complete example looks like this:

using System;
using System.Text.RegularExpressions;

public class Test
{
  public static void Main()
  {
    String text = "/green/blah/agriculture/apple/blah/hallo/apple";
    var regex =  new Regex("^(/(?:green|red)/(?:[^/]+/)*?)apple(/.*)");
    String replacement = "$1$2Orange$4";
    string result = Regex.Replace(text, regex.ToString(), replacement);
    Console.WriteLine(result);
  }
}

And as well a running example is here

See the updated regex, I needed to change it again to capture things like this:

 /green/blah/agriculture/apple/blah/hallo/apple/green/blah/agriculture/apple/blah/hallo/apple

With the above regex it matched the last apple and not the first as prio designated. I changed the regex to this:

var regex =  new Regex("^(/(?:green|red)/(?:[^/]+/)*?)apple(/.*)");

I updated the code as well as the running example.

If you really want to replace only the first occurence of apple and dont mind about the URL structure then can you use one of the following methods:

First simply use apple as regex and use the overloaded Replace method.

using System;
using System.Text.RegularExpressions;

public class Test
{
    public static void Main()
    {
      String text = "/green/blah/agriculture/apple/blah/hallo/apple/green/blah/agriculture/apple/blah/hallo/apple";
      var regex = new Regex(Regex.Escape("apple"));
      String replacement = "Orange";
      string result = regex.Replace(text, replacement.ToString(), 1);
      Console.WriteLine(result);
    }
}

See working Example


Second is the use of IndexOf and Substring which could be much quick as the use of the regex classes.

See the following Example:

   class Program
    {
        static void Main(string[] args)
        {
            string search = "apple";
            string text = "/green/blah/agriculture/apple/blah/hallo/apple/green/blah/agriculture/apple/blah/hallo/apple";
            int idx = text.IndexOf(search);
            int endIdx = idx + search.Length;
            int secondStrLen = text.Length - endIdx;
            if (idx != -1 && idx < text.Length && endIdx < text.Length && secondStrLen > -1)
            {
                string first = text.Substring(0, idx);
                string second = text.Substring(endIdx, secondStrLen);
                string result = first + "Orange" + second;
                Console.WriteLine(result);
            }
        }
    }

Working Example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM