String.Replace()与StringBuilder.Replace()
我有一个string,我需要用字典中的值replace标记。 它必须尽可能高效。 用string.replace做一个循环就会消耗内存(string是不可变的,请记住)。 会StringBuilder.Replace()有什么更好的,因为这是devise用于string操作?
我希望避免RegEx的费用,但如果这将是一个更有效率,那么就这样吧。
注意:我不关心代码的复杂性,只关心它运行的速度和它消耗的内存。
平均统计:字符长255-1024,字典15-30。
使用RedGate Profiler使用下面的代码
class Program { static string data = ""; static Dictionary<string, string> values; static void Main(string[] args) { Console.WriteLine("Data length: " + data.Length); values = new Dictionary<string, string>() { { "ab", "aa" }, { "jk", "jj" }, { "lm", "ll" }, { "yz", "zz" }, { "ef", "ff" }, { "st", "uu" }, { "op", "pp" }, { "x", "y" } }; StringReplace(data); StringBuilderReplace1(data); StringBuilderReplace2(new StringBuilder(data, data.Length * 2)); Console.ReadKey(); } private static void StringReplace(string data) { foreach(string k in values.Keys) { data = data.Replace(k, values[k]); } } private static void StringBuilderReplace1(string data) { StringBuilder sb = new StringBuilder(data, data.Length * 2); foreach (string k in values.Keys) { sb.Replace(k, values[k]); } } private static void StringBuilderReplace2(StringBuilder data) { foreach (string k in values.Keys) { data.Replace(k, values[k]); } } }
- String.Replace = 5.843ms
- StringBuilder.Replace#1 = 4.059ms
- Stringbuilder.Replace#2 = 0.461ms
string长度= 1456
stringbuilder#1在该方法中创build了stringbuilder,而#2则不然,性能差异将最终变成相同,因为您只是将该工作移出该方法。 如果你从一个string开始,而不是一个string,那么#2可能是取而代之的方式。
至于内存,使用RedGateMemory分析器,没有什么可担心的,直到你进入许多replace操作,其中stringbuilder将赢得整体。
这可能有帮助:
简短的答案似乎是String.Replace更快,虽然它可能会有更大的影响你的内存占用/垃圾收集开销。
是的, StringBuilder
会给你速度和内存的增加(基本上是因为它不会创build一个string的实例,每次你会对它进行操作StringBuilder
总是使用相同的对象)。 这里是一些MSDN链接的细节。
会stringbuilder.replace更好[比String.Replace]
是的,好多了。 如果你可以估计新string的上限(看起来你可以),那么它可能会足够快。
当你创build它像:
var sb = new StringBuilder(inputString, pessimisticEstimate);
那么StringBuilder将不必重新分配它的缓冲区。
将数据从一个String转换为一个StringBuilder并返回将需要一些时间。 如果只执行一次replace操作,那么这个时间可能不会被StringBuilder固有的效率提升所弥补。 另一方面,如果将string转换为StringBuilder,然后对其执行多个Replace操作,并在最后将其转换回来,则StringBuilder方法会更快。
而不是在整个string上运行15-30个replace操作,而使用像trie数据结构这样的东西来保存字典可能更有效率。 然后你可以遍历你的inputstring来做所有的search/replace。
这将取决于平均有多less标记出现在给定的string中。
在StringBuilder和String之间search关键字的性能可能是相似的,但是如果必须在单个string中replace多个标记,则StringBuilder将会获胜。
如果您只希望每个string平均有一个或两个标记,并且字典很小,那么我只需要String.Replace。
如果有多个标记,则可能需要定义一个自定义语法来标识标记 – 例如,用大括号括住一个适合文字大括号的转义规则。 然后,您可以实现一个parsingalgorithm,该algorithm遍历string的字符一次,识别并replacefind的每个标记。 或者使用正则expression式。
我的两分钱,我只写了几行代码来testing每种方法如何执行,并且如预期的那样,结果是“取决于”。
对于更长的string正则Regex
似乎performance更好,对于更短的string, String.Replace
它是。 我可以看到, StringBuilder.Replace
用法不是很有用,如果错误地使用,它可能是致命的GC透视(我试图共享一个StringBuilder
实例)。
检查我的StringReplaceTests GitHub回购 。
@DustinDavis的答案的问题是,它recursion操作相同的string。 除非你打算做一个往复式的操作,否则在这种testing中,你应该为每个操作案例分别设置不同的对象。
我决定创build我自己的testing,因为我在networking上发现了一些相互矛盾的答案,我想完全确定。 我正在处理的程序处理大量文本(在某些情况下文件有数万行)。
所以这里有一个快速的方法,你可以复制和粘贴,看看自己哪个更快。 您可能需要创build自己的文本文件进行testing,但是您可以轻松地从任何地方复制和粘贴文本,并为自己创build足够大的文件:
using System; using System.Diagnostics; using System.IO; using System.Text; using System.Windows; void StringReplace_vs_StringBuilderReplace( string file, string word1, string word2 ) { using( FileStream fileStream = new FileStream( file, FileMode.Open, FileAccess.Read ) ) using( StreamReader streamReader = new StreamReader( fileStream, Encoding.UTF8 ) ) { string text = streamReader.ReadToEnd(), @string = text; StringBuilder @StringBuilder = new StringBuilder( text ); int iterations = 10000; Stopwatch watch1 = new Stopwatch.StartNew(); for( int i = 0; i < iterations; i++ ) if( i % 2 == 0 ) @string = @string.Replace( word1, word2 ); else @string = @string.Replace( word2, word1 ); watch1.Stop(); double stringMilliseconds = watch1.ElapsedMilliseconds; Stopwatch watch2 = new Stopwatch.StartNew(); for( int i = 0; i < iterations; i++ ) if( i % 2 == 0 ) @StringBuilder = @StringBuilder .Replace( word1, word2 ); else @StringBuilder = @StringBuilder .Replace( word2, word1 ); watch2.Stop(); double StringBuilderMilliseconds = watch1.ElapsedMilliseconds; MessageBox.Show( string.Format( "string.Replace: {0}\nStringBuilder.Replace: {1}", stringMilliseconds, StringBuilderMilliseconds ) ); } }
我得到了这个string.Replace()每次换出8-10个字母的话大约快20%。 如果你想要自己的经validation据,就自己试试。