String.Replace问题的有效解决方案?

时间:2009-10-27 20:44:10

标签: c# .net string

假设我有一个像这样声明的字符串数组:

String[] strings = new String[ 1024 ];

给出一系列像这样声明的键值对:

KeyValuePair<String, String>[] pairs = new KeyValuePair<String, String>[ 50 ];

解决方案有哪些可行的解决方法:

for ( int i = 0; i < 1024; ++i )
{
  foreach ( var kv in pairs )
  {
      strings[ i ] = strings[ i ].Replace( kv.Key, kv.Value );
  }
}

此代码只是任意的,只是为了显示实际问题。给定了许多在编译时已知的键值,如何进行高效的String.Replace,并可能减少方法调用并复制String(每次调用String.Replace都会产生一个新的不可变String,而不是当有很多替换呼叫时非常有效率?)

5 个答案:

答案 0 :(得分:2)

我会说将字符串转储到List中,然后每个stringbuilders执行replace调用。这将节省额外的不可变字符串对象的创建。如果你只需要少量的替换品,那么很可能会有一点开销,但是既然你已经说过会有很多替换,那么这应该会有所帮助。

答案 1 :(得分:2)

它对循环次数没有帮助,但是如果你使用StringBuilder作为中间件,它会使用相同的参数签名集进行.Replace调用。

编辑:

不确定它是否更快,但您可以将Regex.Replace与评估者委托一起使用。

如果您使用密钥构建搜索正则表达式: (KEY1 | KEY2 | KEY3 | KEY4 ...)

然后将委托传递给.Replace,您可以根据Match的Value属性返回查找。

  public string ReplaceData(Match m)
  {
      return pairs[m.Value];         
  }

...

  pairs.Add("foo","bar");
  pairs.Add("homer","simpson");
  Regex r = new Regex("(?>foo|homer)");
  MatchEvaluator myEval = new MatchEvaluator(class.ReplaceData);
  string sOutput = r.Replace(sInput, myEval);

答案 2 :(得分:1)

您可以使用收到的建议(例如使用StringBuilder)和并行扩展,使用您的计算机中有多少核心来并行完成工作。

看看这段代码:

class Program {

    static void Main(String[] args) {

        // Filling the data
        List<KeyValuePair<String, String>> map = new List<KeyValuePair<String, String>>();
        List<StringBuilder> strings = new List<StringBuilder>();
        List<StringBuilder> strings2 = new List<StringBuilder>();

        for (Int32 i = 0; i < 50; i++) {
            String key = String.Format("[KEY{0}]", i);
            String value = String.Format("Text of KEY{0}", i);
            KeyValuePair<String, String> keyValuePair = new KeyValuePair<String, String>(key, value);
            map.Add(keyValuePair);
        }

        for (Int32 i = 0; i < 1024; i++) {
            StringBuilder text = new StringBuilder();

            foreach (KeyValuePair<String, String> keyValuePair in map) {
                text.AppendFormat("Some text before - {0} - Some text after.", keyValuePair.Key);
                text.AppendLine();
            }

            strings.Add(text);
            strings2.Add(text);
        }


        // Measuring the normal loop
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        foreach (StringBuilder text in strings) {
            foreach (KeyValuePair<String, String> eachMap in map) {
                text.Replace(eachMap.Key, eachMap.Value);
            }
        }

        stopwatch.Stop();

        Console.WriteLine("Time with normal loop: {0}", stopwatch.Elapsed);


        // Measuring the parallel loop
        stopwatch.Reset();
        stopwatch.Start();

        Parallel.ForEach(strings2, text => {
            foreach (KeyValuePair<String, String> eachMap in map) {
                text.Replace(eachMap.Key, eachMap.Value);
            }
        });

        stopwatch.Stop();

        Console.WriteLine("Time with parallel: {0}", stopwatch.Elapsed);
        Console.ReadLine();
    }
}

看看我的nootebook(AMD Turion64 X2 - 2内核)上运行的一些措施:



正常循环的时间:00:00:03.5956428
并行时间:00:00:01.8707367

正常循环的时间:00:00:02.1467821
平行时间:00:00:01.4627365

正常循环的时间:00:00:03.4123084
并行时间:00:00:01.6704408



希望这有帮助。

Ricardo Lacerda Castelo Branco

答案 3 :(得分:0)

这应该通过选择值

来减少字符串操作
 String[] strings = new String[1024];
 KeyValuePair<String, String>[] pairs = new KeyValuePair<String, String>[ 50 ];

 String[] replaced = strings.Select(x => 
                                         pairs.Any( y => y.Key == x ) ? 
                                         pairs.Where( z => z.Key == x).Select( val =>  val.Value).First() :  x )
                            .ToArray();

答案 4 :(得分:0)

我认为Joe和Agent_9191的建议基本相同:

const int NUM_STRINGS = 1024;
string[] strings = new string[NUM_STRINGS];
StringBuilder[] stringBuilders = new StringBuilder[NUM_STRINGS];

// ensure that all StringBuilder objects are initialized
for (int i = 0; i < NUM_STRINGS; i++) {
    stringBuilders[i] = new StringBuilder(strings[i]);
}

KeyValuePair<string, string>[] pairs = new KeyValuePair<string, string>[50];

for (int i = 0; i < NUM_STRINGS; i++) {
    foreach (var kv in pairs) {
         // StringBuilder is mutable;
         // this actually modifies the instance
         stringBuilders[i].Replace(kv.Key, kv.Value);
    }

    strings[i] = stringBuilders[i].ToString();
}