Sean Dooley
Sean Dooley

Reputation: 625

Replacing specific numbers with String.Replace or Regex.Replace

Just having a little problem in attempting a string or regex replace on specific numbers in a string.

For example, in the string

@1 is having lunch with @10 @11

I would like to replace "@1", "@10" and "@11" with the respective values as indicated below.

"@1" replace with "@bob"
"@10" replace with "@joe"
"@11" replace with "@sam"

So the final output would look like

"@bob is having lunch with @joe @sam"

Attempts with

String.Replace("@1", "@bob")

results in the following

@bob is having lunch with @bob0 @bob1

Any thoughts on what the solution might be?

Upvotes: 0

Views: 483

Answers (4)

Konrad Kokosa
Konrad Kokosa

Reputation: 16898

I would prefer more declarative way of doing this. What if there will be another replacements, for example @2 change to luke? You will have to change the code (add another Replace call).

My proposition with declarations of the replacements:

string input = "@1 is having lunch with @10 @11";
var rules = new Dictionary<string,string>() 
{
    { "@1", "@bob" },
    { "@10", "@joe" },
    { "@11", "@sam"}
};

string output = Regex.Replace(input, 
                              @"@\d+", 
                              match => rules[match.Value]);

Explanation:

Regular expression is searching for pattern @\d+ which means @ followed by one or more digits. And replaces this match thanks to MatchEvaluator by the proper entry from the rules dictionary, where the key is the match value itself.

Upvotes: 3

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131601

Assuming all placeholder start with @ and contain only digits, you can use the Regex.Replace overload that accepts a MatchEvaluator delegate to pick the replacement value from a dictionary:

var regex = new Regex(@"@\d+");

var dict = new Dictionary<string, string>
{
    {"@1","@bob"},
    {"@10","@joe"},
    {"@11","@sam"},
};

var input = "@1 is having lunch with @10 @11";
var result=regex.Replace(input, m => dict[m.Value]);

The result will be "@bob is having lunch with @joe @sam"

There are a few advantages compared to multiple String.Replace calls:

  1. The code is more concise, for an arbitrary number of placeholders
  2. You avoid mistakes due to the order of the replacements (eg @11 must come before @1)
  3. It's faster because you don't need to search and replace the placeholders multiple times
  4. It doesn't create temporary strings for each parameter. This can be an issue for server applications because a large number of orphaned strings will put pressure on the garbage collector

The reason for advantages 3-4 is that the regex will parse the input and create an internal representation that contains the indexes for any match. When the time comes to create the final string, it uses a StringBuilder to read characters from the original string but substitute the replacement values when a match is encountered.

Upvotes: 2

Nikhil Agrawal
Nikhil Agrawal

Reputation: 48560

Start with the biggest (read longest) number like @11 and @10 first and then replace @1.

string finalstring = mystring.Replace("@11", "@sam")
                             .Replace("@10", "@joe")
                             .Replace("@1", "@bob");

Upvotes: 1

brantonion
brantonion

Reputation: 47

Make your regular expression look for the string @1_

The space after will ensure that it only gets the number @1.

Upvotes: 0

Related Questions