3

What is the most elegant solution for this task:

There is a template string, for example: "<CustomAction Id=<newGuid> /><CustomAction Id=<newGuid> />" and I need to replace <newGuid> by different Guids.

Generalize the problem:

.Net string class has Replace method that takes 2 parameters: oldValue and newValue of char or string type. Problem is that newValue is static string (not a function returning string).

There is my simple implementation:

public static string Replace(this string str, string oldValue, Func<String> newValueFunc)
    {      
      var arr = str.Split(new[] { oldValue }, StringSplitOptions.RemoveEmptyEntries);
      var expectedSize = str.Length - (20 - oldValue.Length)*(arr.Length - 1);
      var sb = new StringBuilder(expectedSize > 0 ? expectedSize : 1);
      for (var i = 0; i < arr.Length; i++)
      {
        if (i != 0)
          sb.Append(newValueFunc());
        sb.Append(arr[i]);
      }
      return sb.ToString();
    }

Can you suggest more elegant solution?

Ivan Bianko
  • 1,749
  • 15
  • 22
  • 2
    `Regex.Replace` have a similar signature. Might be better to use. – leppie Oct 25 '11 at 09:22
  • 1
    Regex.Replace let's you specify a callback, but you'll have to escape the search string. – H H Oct 25 '11 at 09:24
  • Finally understand what he meant, he wanted each replace occurrence to be the different value of the result of function call... The question is not correctly written, with no example of how the solution should work. – Marcel Valdez Orozco Oct 25 '11 at 12:48

3 Answers3

1

I think it's time to summarize to avoid wrong answers...

The most elegant solution was suggested by leppie and Henk Holterman:

public static string Replace(this string str, string oldValue, Func<string> newValueFunc)
{
  return Regex.Replace( str,
                        Regex.Escape(oldValue),
                        match => newValueFunc() );
} 
Community
  • 1
  • 1
Ivan Bianko
  • 1,749
  • 15
  • 22
  • 3
    This answer doesn't work. Try `"t.e.s.t.".Replace(".", () => "\\\\")` or `"t.e.s.t.".Replace(".", () => "x")`. The return should look like: `return Regex.Replace(str, Regex.Escape(oldValue), match => newValueFunc());`. – Enigmativity Oct 25 '11 at 12:26
  • I don't get it, isn't that what string.Replace does already? Replace a string occurence for another? – Marcel Valdez Orozco Oct 25 '11 at 12:39
  • 1
    @MarcelValdez - It's the use of a `Func` to generate distinct replacements for each occurrence of the found string that is the point of this question. – Enigmativity Oct 25 '11 at 13:14
  • 1
    Yeah, I got it, but the question isn't well formulated in the first place. IMO you shouldn't be downvoting all answers to 're-read' the question, unless the question is crystal-clear, that's just offensive. Everyone answered the wrong question because it wasn't correctly formulated. – Marcel Valdez Orozco Oct 25 '11 at 13:44
0

This works for me:

public static string Replace(this string str, string oldValue,
    Func<String> newValueFunc)
{      
    var arr = str.Split(new[] { oldValue }, StringSplitOptions.None);
    var head = arr.Take(1);
    var tail =
        from t1 in arr.Skip(1)
        from t2 in new [] { newValueFunc(), t1 }
        select t2;
    return String.Join("", head.Concat(tail));
}

If I start with this:

int count = 0;
Func<string> f = () => (count++).ToString();
Console.WriteLine("apple pie is slappingly perfect!".Replace("p", f));

Then I get this result:

a01le 2ie is sla34ingly 5erfect!
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • Yes, it works and it is what i want, but `Regex.Replace` suggested by leppie and HenkHolterman is much more elegant. – Ivan Bianko Oct 25 '11 at 12:01
  • Yes, you're right - the `RegEx` approach is best - when it works. You need to check the comment I put answer the answer. – Enigmativity Oct 25 '11 at 12:28
0

use

Regex.Replace(String, MatchEvaluator)

using System;
using System.Text.RegularExpressions;

class Sample {
//  delegate string MatchEvaluator (Match match);
    static public void Main(){

        string str = "<CustomAction Id=<newGuid> /><CustomAction Id=<newGuid> />";
        MatchEvaluator myEvaluator = new MatchEvaluator(m => newValueFunc());
        Regex regex = new Regex("newGuid");//OldValue
        string newStr = regex.Replace(str, myEvaluator);
        Console.WriteLine(newStr);
    }
    public static string newValueFunc(){
        return "NewGuid";
    }
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70