在C#中优化字符串操作

简介:

性能测试代码:/Files/zhuqil/PerformanceTest.zip 

     程序员通常都希望自己能的编写易读,易维护和易扩展的代码。然而,某些情况下,性能变成最重要的事情。本文提供了几个有用的窍门,来提高你常见的字符串操作的性能。

      最近,我花了很多时间去研究一个简单的代码编辑器。这个应用程序的主要特点之一是语法高亮,实现这样的功能,性能是关键。我花了很多时间来优化我的代码。在做这个项目的同时,我也学到了很多。在这里,我向大家分享一下我的经验。

      附在本文中的项目包含一个简单的基准测试应用程序,来比较下面描述的方法。

  N0.1:在字符串中搜索一个单词

      对字符串进行搜索是一件常见的任务。有几种方法可以做到这一点,下面将讨论每种方法。

1、使用正则表达式

      正则表达式是一个非常强大的,有用的,对于数据验证和字符串搜索是非常快速的 ,但是,当性能很重要,正则表达式可能成为一场噩梦,你可以做几件事,使你的代码运行得更快。

    规则#1:写一个好的正则表达式

    写一个正则表达式可能很容易,但写一个有效的正则表达式,也是一个挑战,优化正则表达式已经超出了本文的范围,有在网络上有许多讨论这一主题文章和书籍。最重要的规则是:保持简单,复杂的规则表达式,包括大量的交替,通常需要很长时间才能执行。

   规则#2:不要使用Regex类的静态方法

Regex类提供了一些静态的方法,进行基本的操作。下面的代码查找字符串变量input 是否包含变量pattern

string  input  =   " The quick brown fox jumps over the lazy dog " ;
string  pattern  =   " fox " ;  
if  (Regex.IsMatch(input, pattern)) {
  
/*  More code here...  */
}     
  

    IsMatch方法根据pattern变量中创建一个Regex对象,然后试着匹配input字符串,这个过程表现地非常缓慢,正则表达式不重复使用,这个才非常有用。

规则#3:尽可能地重复使用Regex对象

如上所述,一个正则表达式对象的创建需要一段时间,你应该避免频繁创建。在某些情况下,您可以在应用程序的启动的时候初始化一切必要的正则表达式,然后多次利用他们来处理长段的文本。这将会提高性能。

规则#4:考虑使用编译的正则表达式

   当创建一个正则表达式对象,如果你使用编译的选项,性能会更好

Regex pattern = new Regex("SomePattern", RegexOptions.Compiled); 

     虽然有几个缺点,编译正则表达式增加了应用程序的启动时间,造成更多的内存使用,Jeff Atwood 写了一篇文章,讨论了编译的正则表达式优势和缺点:

     http://www.codinghorror.com/blog/archives/000228.html 

2、使用indexOf()方法

    在一个字符串内进行搜索的时候,字符串类型IndexOf方法是非常有用的。你应该知道一些东西,来有效使用此方法。

    a、尽量使用char类型

    有两个IndexOf方法重载方法,第一个参数可以是一个字符或一个字符串,使用字符重载方法将快很多。如果您知道您正在搜索字符串的长度为1,请使用char类型代替。

    b、一个不成功搜索所花的时间将超过一个成功的搜索:

    这其实并不奇怪,如果IndexOf方法成功,它将返回给定的字符串或字符首次出现的位置,它省去了剩余字符串的搜索时间。 相反,如果输入的字符串不包含给定的字符或者字符串,IndexOf函数将对整个输入字符串进行搜索。

    c、经常有一种方法来消除不成功的搜索,例如,如果你想知道输入的字符串是否包含了一组单词的,你可以先搜索那些更可能出现在输入字符串的字符。

3、从零开始写的文本搜索的方法

    现在,到了的最有趣的部分。IndexOf方法搜索一个字符时是相当快的,但搜索一个单词是缓慢的,如何有一个更快的方式在字符串内搜索单词呢?

    花了一些时间,为寻找可能最快的的解决办法,以下方法是我想出的。

代码

    此函数基于IndexOf方法搜索一个字符非常快这个事实的。

    基本想法非常的简单,这个方法先搜索这个单词的第一个字符。如果一旦找到,它检测下一个的字符,该代码是有点乱,因为它包含了很多小的优化。例如,我发现,如果该方法在启动检测这个词的其余部分的“for”循环之前检查第二个字符(第一个已近被找到),平均性能将会更好。

    我已经对随机生成的字符串进行大量测试,比较上述所列三种方案和这里是结果:

    a、对一个单词的搜索,IndexOf函数速度总是比我的自定义FastIndexOf方法慢20%左右。
    b、如果输入字符和匹配字符串都足够的长,正则表达式是最快的方式找到一个字符串,
    下图是根据我的测量的值。它显示了两种最快的办法取决于输入字符串的长度:
    纵轴表示这个词的长度(以字符数),横轴显示的是(以字符)输入字符串的长度。条纹地区是自定义搜索方法优于正则表达式。
请注意,所有测量值是近似的。
N0.2:替换转义字符
    另一种常见的字符串的操作是要替换转义字符。有时替换是很容易的,你只需要设立一个反斜杠(或其他字符)在每一个转义字符的前面。
     试想以下情况:你是建立一个RTF文件,你要在文件中的插入字符串。在RTF文件中"(",")"和"\"字符具有特殊的意义,因此,必须先用反斜杠。现在的问题是:什么是最快的方法,以取代相应的转义序列的每个字符?
正则表达式
1、 用Regex类的 Replace 法是其中一个可行办法。但是,在这种情况下,使用正则表达式是目前最慢的选择。
2、字符串的 Replace() 方法
string  input;

/*  ....  */

input.Replace(
" \\ " " \\\\ " ).Replace( " { " " \\{ " ).Replace( " } " " \\} " ); 

    另一种简单的方法是使用的字符串类型Replace方法,当建立RTF文件,该更换程序将如下:这个易读,简短和干净的,但它并不总是最快的选择。

3、从头编写一个自定义方法
     就像前面的情况,我想编写一个定制的方法,完成相同的任务。以下是代码:
代码

      第一个参数是输入字符串,第二个是一个被转义字符数组,最后一个参数是转义字符,正如你可能知道,如果你需要做连续许多操作,直接编辑字符串的效率不是很高。StringBuilder类提供了一种有效的方式来编辑字符串,虽然它需要一点时间来初始化一个StringBuilder对象,如果你知道你需要反复编辑字符串,这需要合理的使用StringBuilder。

    我创建的另一个种使用StringBuilder方法:
代码

    我使用了3个方法来取代转义序列的3字符集描述方法。下图显示,该方法是最快的一个取决于输入字符串:

 
    纵轴显示转义字符串中的字符数,而横轴显示出现的转义字符频率的百分比。频率为50,即每输入字符串的都需要其他字符转义,频率为1,只有1%的字符输入字符串(每100字符)是转义的。
    如果有足够的字符进行转义,如果转义字符频率足够高(带区面积的左上图的右上角),String.Replace方法证明是最快的。
    图的其他部分显示:在大多数情况下,自定义字符转义方法是最快的选择。正如所料,如果替换的字符数足够多,在大约5个字符的情况下,该StringBuilder的方法更快。
    如果你想知道有点串更多string/StringBuilder 的性能比较,我建议以下的2个资源:

    Concatenating Strings Efficiently by Jon Skeet 

    StringBuilder vs String by Alois Kraus 

    如果你想要很高的性能,你必须知道处理的数据是什么样的,像我一样,你将不得不花一些时间比较所有可供选择。
    我希望这篇文章给你一个正确的方向,帮助你提高你的代码的性能。希望得到你的回复!
    参考原文:http://www.codeproject.com/KB/string/string_optimizations.aspx




本文转自麒麟博客园博客,原文链接:http://www.cnblogs.com/zhuqil/archive/2010/01/08/1641767.html,如需转载请自行联系原作者
 
 

 

相关文章
|
6月前
|
C#
C#的小例子和字符串(一)
C#的小例子和字符串(一)
142 0
|
6月前
|
C#
C#有关字符串的分割,替换,截取
C#有关字符串的分割,替换,截取
|
1月前
|
开发框架 .NET C#
C#|.net core 基础 - 删除字符串最后一个字符的七大类N种实现方式
【10月更文挑战第9天】在 C#/.NET Core 中,有多种方法可以删除字符串的最后一个字符,包括使用 `Substring` 方法、`Remove` 方法、`ToCharArray` 与 `Array.Copy`、`StringBuilder`、正则表达式、循环遍历字符数组以及使用 LINQ 的 `SkipLast` 方法。
|
2月前
|
开发框架 .NET 程序员
C# 去掉字符串最后一个字符的 4 种方法
在实际业务中,我们经常会遇到在循环中拼接字符串的场景,循环结束之后拼接得到的字符串的最后一个字符往往需要去掉,看看 C# 提供了哪4种方法可以高效去掉字符串的最后一个字符
250 0
|
2月前
|
前端开发 C#
C# 一分钟浅谈:字符串操作与正则表达式
本文详细介绍C#中的字符串操作与正则表达式应用,涵盖字符串拼接、分割、查找及替换等基础操作,并通过实例讲解正则表达式的模式匹配、文本替换与分组捕获技巧。同时,文章还探讨了性能优化、复杂度管理和安全性等问题及解决策略,助你提升编程效率,应对实际开发挑战。
72 0
|
4月前
|
SQL 开发框架 前端开发
在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式
在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式
|
3月前
|
缓存 NoSQL Redis
【Azure Redis 缓存】C#程序是否有对应的方式来优化并缩短由于 Redis 维护造成的不可访问的时间
【Azure Redis 缓存】C#程序是否有对应的方式来优化并缩短由于 Redis 维护造成的不可访问的时间
|
5月前
|
C#
技术经验分享:c#拆分字符串英文和数字(包括国外所以文字)
技术经验分享:c#拆分字符串英文和数字(包括国外所以文字)
34 0
技术经验分享:c#拆分字符串英文和数字(包括国外所以文字)
|
5月前
|
C#
C# 中的字符与字符串
C# 中的字符与字符串
|
6月前
|
缓存 算法 测试技术
优化 C#编程性能的策略
【4月更文挑战第20天】优化C#性能策略包括:选择合适算法和数据结构,避免频繁对象创建,缓存常用数据,减少内存分配,使用异步编程,优化数据库操作(如合理查询和使用索引),利用多线程并行处理,精简代码,使用性能分析工具,硬件升级,以及进行性能测试。综合应用这些策略可提升程序性能和响应性。
63 4