61

My code uses String.Replace several times in a row:

mystring = mystring.Replace("somestring", variable1);
mystring = mystring.Replace("somestring2", variable2);
mystring = mystring.Replace("somestring3", variable1);

I suspect there's a better and faster way to do it. What would you suggest?

4444
  • 3,541
  • 10
  • 32
  • 43
Petter Brodin
  • 2,069
  • 4
  • 21
  • 27
  • 1
    If `variable1` contains the text `"somestring2"`, then what is your preferred behaviour for this? Or what if `variable1` is `"g2"` and `mystring` was `"somestrinsomestring"`, then what would be the preferred behaviour? – Strategy Thinker May 06 '17 at 20:23

8 Answers8

69

For an 'easy' alternative just use a StringBuilder....

StringBuilder sb = new StringBuilder("11223344");

string myString =
    sb
      .Replace("1", string.Empty)
      .Replace("2", string.Empty)
      .Replace("3", string.Empty)
      .ToString();
Rostov
  • 2,516
  • 2
  • 23
  • 17
36

Are we going for ways to make this harder to understand what is going on?

If so regex is your friend

var replacements = new Dictionary<string,string>()
{
   {"somestring",someVariable1},
   {"anotherstring",someVariable2}
};

var regex = new Regex(String.Join("|",replacements.Keys.Select(k => Regex.Escape(k))));
var replaced = regex.Replace(input,m => replacements[m.Value]);

Live: http://rextester.com/SXXB8348

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • 1
    Looks good, but you'll want to call `Regex.Escape` around the dic keys when compiling the regex. Also note it won't technically do the same thing. It may work for the OP's test cases, but in theory if you had something like, replacing "1" with "2" and then "2" with "3" the OP's code would result in each "1" becoming a "3" and yours would end up resulting in a "2". As long as you aren't actually replacing something that's been replaced in a previous iteration with the OP's example, then this will work just fine. – Servy Aug 17 '12 at 14:15
  • 4
    @Servy - You make all good points. However, my initial sentence should have pointed out that this is a bloody awful way of doing multiple replaces. – Jamiec Aug 17 '12 at 15:06
  • @Jamiec: What's wrong with this? It might only have to read the string once, will only have to copy the string once, lets you easily look for whole words, lets you do proper capitalization on words, and lets you do things like escape strings (e.g. `&`=>`&`, `"`=>`"`) without worrying about what order the replacements happen in. – Gabe Sep 30 '13 at 05:28
  • 2
    This is (unfortunately) much slower than calling string.Replace() multiple times. I'm also looking for a faster way to do this; it seems such a waste to loop through a string multiple times. – Orestis P. Oct 01 '13 at 23:02
  • 3
    This RegEx solution makes a single pass and replaces all items correctly. In some circumstances (like mine) this is the ONLY option and calling .Replace does not work. Why? Consider the case where variable1 CONTAINS, in part, the string "somestring2". Then the second .Replace winds up clobbering the first thing you wanted to replace, etc. – Ray Ackley Sep 26 '14 at 17:32
  • @Jamiec what do you think about this article : https://blogs.msdn.microsoft.com/debuggingtoolbox/2008/04/02/comparing-regex-replace-string-replace-and-stringbuilder-replace-which-has-better-performance/ – Manoochehr Dadashi Jun 15 '16 at 20:17
  • Even if this post is old, I'd like to mention that this solution is far better than accepted one, as it avoids "chain replacing" problems too. – Siegfried.V Jun 04 '21 at 07:33
27

You could at least chain the statements:

mystring = mystring.Replace("somestring", variable1)
                   .Replace("somestring2", variable2)
                   .Replace("somestring3", variable3); 
Athena
  • 3,200
  • 3
  • 27
  • 35
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
15

Calling Replace three times is not only a valid answer, it might be the preferred one:

RegEx takes three steps: Parse, Execute, Formulate. But String.Replace is hard-coded, so in many cases it has superior speed. And a complex RegEx isn't as readable as a well-formatted chain of Replace statements. (Compare Jonathan's solution to Daniel's)

If you're still not convinced that Replace is better for your case, make a competition out of it! Try both methods side-by-side and use a Stopwatch to see how many milliseconds you save when using your data.

But DON'T optimize prematurely! Any developer will prefer readability and maintainability over a cryptic pile of spaghetti that performs three milliseconds faster.

4444
  • 3,541
  • 10
  • 32
  • 43
5

This article Regex: replace multiple strings in a single pass with C# can be helpful:

static string MultipleReplace(string text, Dictionary replacements) {
    return Regex.Replace(text, 
        "(" + String.Join("|", adict.Keys.ToArray()) + ")",
        delegate(Match m) { return replacements[m.Value]; }
    );
}

// somewhere else in code
string temp = "Jonathan Smith is a developer";
adict.Add("Jonathan", "David");
adict.Add("Smith", "Seruyange");
string rep = MultipleReplace(temp, adict);
Pedro Estrada
  • 2,384
  • 2
  • 16
  • 24
Jonathan Simon Prates
  • 1,122
  • 2
  • 12
  • 28
  • 2
    This is essentially the same as Jamiec's answer, but without the (required) escaping. – Eric Aug 25 '12 at 16:09
4

Depending how your data is organized (what you're replacing) or how many you have; an array and loops might be a good approach.

string[] replaceThese = {"1", "2", "3"};
string data = "replace1allthe2numbers3";

foreach (string curr in replaceThese)
{
    data = data.Replace(curr, string.Empty);
}
Matt Razza
  • 3,524
  • 2
  • 25
  • 29
3

If you don't want to use RegEx add this class to your project,
It uses an extension method 'MultipleReplace':

public static class StringExtender
{
    public static string MultipleReplace(this string text, Dictionary<string, string> replacements)
    {
        string retVal = text;
        foreach (string textToReplace in replacements.Keys)
        {
            retVal = retVal.Replace(textToReplace, replacements[textToReplace]);
        }
        return retVal;
    }
}

Then you can use this piece of code:

 string mystring = "foobar";

 Dictionary<string, string> stringsToReplace = new Dictionary<string,string>();
 stringsToReplace.Add("somestring", variable1);
 stringsToReplace.Add("somestring2", variable2);
 stringsToReplace.Add("somestring3", variable1);

 mystring = mystring.MultipleReplace(stringsToReplace);
mathijsuitmegen
  • 2,270
  • 1
  • 34
  • 36
  • upvoted this one. it allows you to build up the filters say from a datatable which is super helpful. So when you have many filters (50 in my case) and you have 1k sentences to go through, this is the cat's meow. – Rob Sep 25 '19 at 22:51
  • This answer encourages bad practices when dealing with an unbounded number of strings. It should be edited to use a `StringBuilder` in the implementation otherwise it becomes a huge memory waster. – julealgon Sep 01 '22 at 15:32
1

My preferred method is to use the power of Regex to solve a multiple replace problem. The only issue with this approach is you only get to choose one string to replace with.

The following will replace all '/' or ':' with a '-' to make a valid file name.

Regex.Replace("invalid:file/name.txt", @"[/:]", "-");
Isaac Baker
  • 323
  • 2
  • 10