开发者

How do you perform string replacement on just a subsection of a string?

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.


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.


To start, try something like this:

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


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;
    }


You have a bug in that you will miss the item to replace if it is in the beginning.

change these lines;

  int ret = start;  // instead of zero, or you ignore the start parameter

  // Find the next instance of the search string
  // Do not skip olen for the first search!
  int x = i == 0 ? source.IndexOf(org, ret) : source.IndexOf(org, ret + olen);

Also your routine does 300 thousand replaces a second on my machine. Are you sure this will be a bottleneck?

And just found that your code also has an issue if you replace larger texts by smaller texts.


This code is 100% faster if you have four replaces and around 10% faster with one replacement (faster when compared with the posted original code). It uses the specified start parameter and works when replacing larger texts by smaller texts.

Mark Gravells solution is (no offense ;-) 60% slower as the original code and it also returns another value.

    // Method signature, Only replaces first instance or how many are specified in max
    public static int MyReplace(ref string source, string org, string replace, int    start, int max)
    {
        var ret = 0;
        int x = start;
        int reps = 0;
        int l = source.Length;
        int lastIdx = 0;
        string repstring = "";

        while (x < l)
        {
            if ((source[x] == org[0]) && (reps < max) && (x >= start))
            {
                bool match = true;
                for (int y = 1; y < org.Length; y++)
                {
                    if (source[x + y] != org[y])
                    {
                        match = false;
                        break;
                    }
                }
                if (match)
                {
                    repstring += source.Substring(lastIdx, x - lastIdx) + replace;
                    ret = x;
                    x += org.Length - 1;
                    reps++;
                    lastIdx = x + 1;
                    // Done?
                    if (reps == max)
                    {
                        source = repstring + source.Substring(lastIdx);
                        return ret;
                    }
                }
            }
            x++;
        }

        if (ret > 0)
        {
            source = repstring + source.Substring(lastIdx);
        }

        return ret;
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜