【问题标题】:How do you perform string replacement on just a subsection of a string?如何仅对字符串的一小部分执行字符串替换?
【发布时间】:2011-01-06 10:16:40
【问题描述】:

我想要一种有效的方法,可以像这样工作

编辑:对不起,我没有把我之前尝试过的东西放上去。我现在更新了示例。

// 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

我问的唯一原因是因为我想象我的实现会因为 1000 次替换而变慢。

【问题讨论】:

    标签: c# string performance replace


    【解决方案1】:

    如果您有四次替换,此代码的速度会快 100%,而使用一次替换的速度会快 10%(与发布的原始代码相比更快)。它使用指定的开始参数,并在用较小的文本替换较大的文本时起作用。

    Mark Gravells 解决方案(无意冒犯 ;-) 比原始代码慢 60%,而且它还返回另一个值。

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

    【讨论】:

      【解决方案2】:

      您有一个错误,如果要替换的项目位于开头,您将错过它。

      更改这些行;

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

      你的例程在我的机器上每秒替换 30 万次。你确定这会成为瓶颈吗?

      刚刚发现如果您将较大的文本替换为较小的文本,您的代码也会出现问题。

      【讨论】:

        【解决方案3】:

        仅替换第一个匹配项:

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

        【讨论】:

          【解决方案4】:

          怎么样:

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

          它使用StringBuilder 来避免大量中间strings;我没有严格测试它,但它似乎有效。当没有匹配项时,它还会尝试避免额外的string

          【讨论】:

            【解决方案5】:

            首先,请尝试以下操作:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-03-04
              • 2022-12-28
              • 1970-01-01
              • 1970-01-01
              • 2022-07-18
              • 1970-01-01
              • 2011-08-10
              • 1970-01-01
              相关资源
              最近更新 更多