views:

564

answers:

3

I'd like an efficient method that would work something like this

EDIT: Sorry I didn't put what I'd tried before. I updated the example now.

// Method signature, Only replaces first instance or how many are specified in max
public int MyReplace(ref string source,string org, string replace, int start, int max)
{
     int ret = 0;
     int len = replace.Length;
     int olen = org.Length;
     for(int i = 0; i < max; i++)
     {
          // Find the next instance of the search string
          int x = source.IndexOf(org, ret + olen);
          if(x > ret)
             ret = x;
          else
             break;

         // Insert the replacement
         source = source.Insert(x, replace);
         // And remove the original
         source = source.Remove(x + len, olen); // removes original string
     }
     return ret;
}

string source = "The cat can fly but only if he is the cat in the hat";
int i = MyReplace(ref source,"cat", "giraffe", 8, 1); 

// Results in the string "The cat can fly but only if he is the giraffe in the hat"
// i contains the index of the first letter of "giraffe" in the new string

The only reason I'm asking is because my implementation I'd imagine getting slow with 1,000s of replaces.

+1  A: 

To start, try something like this:

int count = 0;
Regex.Replace(source, Regex.Escape(literal), (match) =>
{
    return (count++ > something) ? "new value" : match.Value;
});
Rubens Farias
+2  A: 

How about:

public static int MyReplace(ref string source,
    string org, string replace, int start, int max)
{
    if (start < 0) throw new System.ArgumentOutOfRangeException("start");
    if (max <= 0) return 0;
    start = source.IndexOf(org, start);
    if (start < 0) return 0;
    StringBuilder sb = new StringBuilder(source, 0, start, source.Length);
    int found = 0;
    while (max-- > 0) {
        int index = source.IndexOf(org, start);
        if (index < 0) break;
        sb.Append(source, start, index - start).Append(replace);
        start = index + org.Length;
        found++;
    }
    sb.Append(source, start, source.Length - start);
    source = sb.ToString();
    return found;
}

it uses StringBuilder to avoid lots of intermediate strings; I haven't tested it rigorously, but it seems to work. It also tries to avoid an extra string when there are no matches.

Marc Gravell
A: 

To replace only the first match:

    private string ReplaceFirst(string source, string oldString, string newString)
    {
        var index = source.IndexOf(oldString);
        var begin = source.Substring(0, index);
        var end = source.Substring(index + oldString.Length);
        return begin + newString + end;
    }
Dmitry Y.