C#学习教程:替换超大字符串中多个字符串的最快方法500)个子字符串。无论我尝试过什么,String.Replace似乎都是最快的方法。我只关心最快的方法。不是代码可读性、可维护性等。我不关心我是否需要使用不安全代码或预处理原始字符串。编辑:我在评论后添加了更多细节:每次替换迭代都会用其他字符串替换字符串上的ABC(每次替换迭代都不同)。要替换的字符串始终相同-ABC将始终为ABC。从来没有ABD。所以如果有400.000次替换迭代。每次使用相同的字符串-ABC-都将被替换为不同的(不同的)字符串。我可以控制ABC是什么。只要不影响结果,我可以让它超短或超长。显然,ABC不能说你好,因为在大多数输入字符串中,hello将作为一个词存在。输入示例:ABCDABCABCDABCABCDABCABCDABCD示例替换为字符串:BC示例替换为字符串:AA,BB,CC,DD,EE(5iterations)示例输出:AAADAAAAAADAAAAAADAAAAAADAAADABBDABBABDBABBABBDABBABBBDABBDACCDACCACCDACCACCDACCACCDACCDADDDADDADDDADDDDADDADDDADDDAEEDAEEAEEDAEEEAEEDAEAEEEDAEED平均情况:输入字符串为100-200kb,替换0次迭代0次。最坏情况:输入字符串为1-2mb,400,000次替换迭代。我什么事都能做。并行进行,不安全地进行等等。无论我做什么。重要的是它需要尽可能快。谢谢由于我对这个问题有点兴趣,所以我已经制定了一些解决方案。通过硬核优化,可以进一步降低成本。要获取最新的来源:https://github.com/ChrisEelmaa/StackOverflow/blob/master/FastReplacer.cs和输出-----------------------------------------------------|实施|平均|个人跑步||--------------------+--------+--------------------||简单|3485|9002,4497,443,0||简单并行|1298|3440,1606,146,0||并行子串|470|1259,558,64,0||不安全+unmanaged_mem|92|229,114,18,8|-------------------------------------------------------在制作自己的替代方法方面,您不可能打败.NET人员,使用它可能已经不安全了。如果您是用C语言完成的,我相信您可以将它降低两倍。我的实现可能是错误的,但你可以得到大致的想法。使用不安全并编译为x64结果:实施|执行|GC#1简单|4706毫秒|0ms#2简单并行|2265毫秒|0ms#3ParallelSubstring|800毫秒|21毫秒#4Fredou不安全|432毫秒|并用这个替换我以前的代码。我不认为我会再做一次迭代,但我确实学到了一些不安全的东西,这是一件好事:-)privateunsafestaticvoidFredouImplementation(stringinput,intinputLength,stringreplace,string[]replaceBy){varindexes=新列表();//输入="ABCDABCABCDABCABCDABCABCDABCD";//输入长度=输入长度;//replaceBy=newstring[]{"AA","BB","CC","DD","EE"};//我自己的string.indexof节省几msintlen=inputLength;fixed(char*i=input,r=replace){intreplaceValAsInt=*((int*)r);while(--len>-1){if(replaceValAsInt==*((int*)&i[len])){indexes.Add(len--);}}}varidx=indexes.ToArray();len=index.Count;Parallel.For(0,replaceBy.Length,l=>Process(input,inputLength,replaceBy[l],idx,len));}privateunsafestaticvoidProcess(stringinput,intlen,stringreplaceBy,int[]idx,intidxLen){varoutput=newchar[len];fixed(char*o=output,i=input,r=replaceBy){intreplaceByValAsInt=*((int*)r);//直接复制,模拟字符串。复制同时(--len>-1){o[len]=i[len];}while(--idxLen>-1){((int*)&o[idx[idxLen]])[0]=replaceByValAsInt;}}//Console.WriteLine(output);听起来你在标记字符串?我会考虑生成一个缓冲区并为您的令牌编制索引或使用模板引擎作为一个简单的示例,您可以使用代码生成来制作以下方法publicstringProduce(stringtokenValue){varbuilder=newStringBuilder();建设者追加(“A”);builder.Append(tokenValue);builder.Append("D");返回builder.ToString();如果您运行迭代次数足够多,那么构建模板的时间就会收回成本。然后您还可以并行调用该方法,没有副作用。也看看你的字符串练习我对Fredou的代码做了一个变体,它需要更少的比较,因为它适用于int*而不是char*。对于长度为n的字符串,它仍然需要n次迭代,只是进行更少的比较。如果字符串以2对齐(因此要替换的字符串只能出现在索引0、2、4、6、8等处),或者如果它以4对齐(你可以'使用long*)。我不太擅长像这样摆弄小东西,所以有人可能会在我的代码中发现一些明显的缺陷,这些缺陷可能会更有效率。我验证了我的更改结果与简单字符串的结果相同。替换。此外,我预计500xstring.Copy会有所收获。string.Copy一下,还没研究。我的结果(FredouII):实施|执行女士|GCMS#1简单|6816|0#2简单并行|4202|0#3平行子串|27839|4#4弗雷多一世|2103|106#5弗雷多二世|1334|91所以大约是时间的2/3(x86,但x64大致相同)。对于这段代码:privateunsafestructTwoCharStringChunk{publicfixedcharchars[2];}privateunsafestaticvoidFredouImplementation_Variation1(stringinput,intinputLength,stringreplace,TwoCharStringChunk[]replaceBy){varoutput=newstring.LplaceB;y[replace]for(vari=0;iProcess_Variation1(output[l],输入,inputLength,replaceBy[l]));}私人静态TwoCharStringChunk_staticToReplace;privatestaticunsafevoidProcess_Variation1(stringoutput,stringinput,intlen,TwoCharStringBuy)replace{intn=0;intm=len-1;fixed(char*i=input,o=output,chars=_staticToReplace.chars){varreplaceValAsInt=*((int*)chars);varreplaceByValAsInt=*((int*)replaceBy.chars);while(这里不需要n个固定缓冲区的结构,可以用简单的int字段代替,但是将char[2]扩展为char[3],这段代码也可以用于三字母字符串,如果是一个int字段。它还需要对Program.cs进行一些更改,所以这里是完整的要点:https://gist.github.com/JulianR/7763857编辑:我不知道为什么我的ParallelSubstring这么慢。我在发布模式下运行.NET4,没有调试器,在x86或x64中。由于您的输入字符串可能长达2Mb,因此我预计不会出现任何内存分配问题。您可以将所有内容加载到内存中并替换数据。如果从BC你总是需要替换AA,一个String.Replace就可以了。但是,如果您需要更多控制,可以使用Regex.Replace:varinput="ABCDABCABCDABCABCDABCABCDABCD";varoutput=Regex.Replace(input,"BC",(match)=>{//在这里你可以添加一些果汁,比如计数器等return"AA";});您可能不会比String.Replace更快(除非您是本地人),因为iircString.Replace是在CLR本身中实现的,以实现最佳性能。如果您想要100%的性能,您可以通过C++/CLI方便地与本机ASM代码交互,然后从那里开始。我的方法有点像模板——它接受一个输入字符串并提取(删除)要替换的子字符串。然后它将获取字符串的其余部分(模板)并将它们与新的替换子字符串组合。这是在构建输出字符串的并行操作(模板+每个替换字符串)中完成的。我想我上面解释的可能更清楚。使用上面的示例输入:constcharsplitter='t';//使用不会出现在字符串中的字符stringinput="ABCDABCABCDABCABCDABCABCDABCD";字符串oldString="BC";string[]newStrings={"AA","BB","CC","DD","EE"};//在输入中,将oldString替换为制表符,以便我们稍后进行String.SplitvarinputTabbed=input.Replace(oldString,splitter.ToString());//ABCDABCABCDABCABCDABCABCDABCD-->AtDAtAtDAtDAtDAtAtDAtDvarinputs=inputTabbed.Split(splitter);/*输入(模板)现在包含:[0]"A"[1]"DA"[2]"A"[3]"DA"[4]"A"[5]"DA"[6]"A"[7]"DA"[8]"D"*///同时,使用模板(inputs)//和替换字符串(newStrings)构建输出varoutputs=newList();Parallel.ForEach(newStrings,iteration=>{varoutput=string.Join(iteration,inputs);//只锁定列表操作lock(outputs){outputs.Add(output);}});foreach(输出中的var输出)Console.WriteLine(输出);输出:AAADAAAAAADAAAAAADAAAAAADAAADABBDABBABBDABBABBDABBABBDABBDACCDACCACCDACCACCDACCACCDACCDADDDADDADDDADDADDDADDADDDADDDAEEDAEEAEEDAEEAEEDAEEAEEDAEED所以你可以做一个比较,这是一个完整的方法,可以在Erti-ChrisEelmaa的测试代码中使用:privatestaticvoidTemplatingImp(stringinput,stringreplaceWhat,IEnumerablereplaceIterations){constcharsplitter='t';//useacharthatwillnotappearinyourstringvarinputTabbed=input.Replace(replaceWhat,splitter.ToString());varinputs=inputTabbed.Split(splitter);//Inparallel,buildtheoutputusingthesplitparts(inputs)//andthereplacementstrings(newStrings)//varoutputs=newList();Parallel.ForEach(replaceIterations,iteration=>{varoutput=string.Join(iteration,inputs);});}IhadasimilarproblemonaprojectwhereIhadimplementedaRegexsolutiontoperformmultiplecase-insensitivereplacementsonafileForefficiencypurposes,Isetthecriteriatoonlypasstherawstringonce.我在https://github.com/nmcc/Spikes/tree/master/StringMultipleReplacements发布了一个简单的控制台应用程序来测试一些策略Regex解决方案代码类似于:Dictionaryreplacements=newDictionary(StringComparer.OrdinalIgnoreCase);//用适当的替换填充字典:StringBuilderpatternBuilder=newStringBuilder();patternBuilder.Append('(');boolfirstReplacement=true;foreach(varreplacementinreplacements.Keys){if(!firstReplacement)patternBuilder.Append('|');elsefirstReplacement=false;patternBuilder.Append('(');patternBuilder.Append(Regex.Escape(replacement));patternBuilder.Append(')');}patternBuilder.Append(')');varregex=newRegex(patternBuilder.ToString(),RegexOptions.IgnoreCase);返回regex.Replace(sourceContent,newMatchEvaluator(match=>replacements[match.Groups[1].Value]));编辑:在我的电脑上运行测试应用程序的执行时间是:更多关于C#的学习教程,希望大家多多关注---本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如有转载请注明出处:
