对于字符串的拼接自己一直有疑问,在何时该用什么方法来拼接?哪种方法更好、更适合。

几种方法


1、“+” 拼接字符串

现在在 C# 中,字符串进行拼接,可以直接用 “+” 而且可以直接用于数字类型的而不必转换(整形、浮点等都可以)

string a = "";

a = a + "";

string b = "" + 1.2345;

对于使用多个 “+” 的,编译器会优化为:

 string a = "a" +  + "b" +  + "c" +  + "d" + ;
string a = string.Concat(new string[]{});

通过分析string.Concat(params string[] values)的实现可以知道:先计算目标字符串的长度,然后申请相应的空间,最后逐一复制,时间复杂度为o(n),常数为1。

固定数量的字符串连接效率最高的是+。

但是字符串的连+不要拆成多条语句,比如:

            string a = "a";
a += ;
a += "b";
a += ;
a += "c";
a += ;

这样的代码,不会被优化为string.Concat,就变成了性能杀手,因为第i个字符串需要复制n-i次,时间复杂度就成了o(n^2)。

那么用 “+” 拼接字符串也是要正确运用。

2、string.Format 拼接字符串

该形式可以同时拼接多个字符串

string.Format("{0}{1}{2}{3}","a","b","c","d");

它的底层是 StringBuilder,在此基础进行了多层的封装,说是效率和 StringBuilder 差不多,这个不清楚,可以看下面的实验;

3、StringBuilder 拼接字符串

StringBuilder str = new StringBuilder();
str.Append("a");

StringBuilder 只分配一次内存,如果第二次连接内存不足,则修改内存大小;它每次默认分配16字节,如果内存不足,则扩展到32字节,如果仍然不足,继续成倍扩展。

如果频繁的扩展内存,效率大打折扣,因为分配内存,时间开销相对比较大。如果事先能准确估计程序执行过程中所需要的内存,从而一次分配足内存,效率大大提高。

如果字符串的数量不固定,就用StringBuilder,一般情况下它使用2n的空间来保证o(n)的整体时间复杂度,常数项接近于2。

因为这个算法的实用与高效,.net类库里面有很多动态集合都采用这种牺牲空间换取时间的方式,一般来说效果还是不错的。

4、List<string> 拼接字符串

            List<string> str =new List<string>();
str.Add("");
str.Add("a");
str.Add("");
str.Add("b");
string.Join("",str);

它可以转换为string[]后使用string.Concat或string.Join,很多时候效率比StringBuiler更高效。List与StringBuilder采用的是同样的动态集合算法,时间复杂度也是O(n),与StringBuilder不同的是:List的n是字符串的数量,复制的是字符串的引用;StringBuilder的n是字符串的长度,复制的数据。不同的特性决定的它们各自的适应环境,当子串比较大时建议使用List<string>,因为复制引用比复制数据划算。而当子串比较小,比如平均长度小于8,特别是一个一个的字符,建议使用StringBuilder。

MSDN中关于StringBuilder的性能注意事项:

Concat 和 AppendFormat 方法都将新数据串连到一个现有的 String 或 StringBuilder 对象。String 对象串联操作总是用现有字符串和新数据创建新的对象。StringBuilder 对象维护一个缓冲区,以便容纳新数据的串联。如果有足够的空间,新数据将被追加到缓冲区的末尾;否则,将分配一个新的、更大的缓冲区,原始缓冲区中的数据被复制到新的缓冲区,然后将新数据追加到新的缓冲区。

String 或 StringBuilder 对象的串联操作的性能取决于内存分配的发生频率。String 串联操作每次都分配内存,而 StringBuilder 串联操作仅当 StringBuilder 对象缓冲区太小而无法容纳新数据时才分配内存。因此,如果串联固定数量的 String 对象,则 String 类更适合串联操作。这种情况下,编译器甚至会将各个串联操作组合到一个操作中。如果串联任意数量的字符串,则 StringBuilder 对象更适合串联操作;例如,某个循环对用户输入的任意数量的字符串进行串联。

测试

测试1:

            Stopwatch watch = new Stopwatch();
watch.Start(); string a = ""; for (int i = ; i < ; i++)
{
a = a + "" ;
} watch.Stop(); Console.WriteLine("+ 用时:" + watch.ElapsedMilliseconds + " ms"); string b = "";
watch.Restart(); for (int i = ; i < ; i++)
{
b = string.Format("{0}{1}", b, "");
} watch.Stop(); Console.WriteLine("Format 用时:" + watch.ElapsedMilliseconds + " ms"); StringBuilder str = new StringBuilder();
char charT = '';
watch.Restart(); for (int i = ; i < ; i++)
{
str.Append("");
} watch.Stop(); Console.WriteLine("StringBuilder 用时:" + watch.ElapsedMilliseconds + " ms");

对上面的几种分别进行100000 次循环,并计时,结果是:

进行1000000 次循环拼接字符串时,时间太长,没有截图

从上面两个来看,String.Format 效率并不高,远远达不到 StringBuildr 的效率,也差于 “+” 拼接字符串;

对代码进行改进:

            Stopwatch watch = new Stopwatch();
watch.Start(); string a = ""; for (int i = ; i < ; i++)
{
a = a + "" + "" + "" + "" + "" + "" + "" + "" + "" + "";
} watch.Stop(); Console.WriteLine("+ 用时:" + watch.ElapsedMilliseconds + " ms"); string b = "";
watch.Restart(); for (int i = ; i < ; i++)
{
b = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}", b, "", "", "", "", "", "", "", "", "", "");
} watch.Stop(); Console.WriteLine("Format 用时:" + watch.ElapsedMilliseconds + " ms"); StringBuilder str = new StringBuilder();
char charT = '';
watch.Restart(); for (int i = ; i < ; i++)
{
str.Append(charT, );
} watch.Stop(); Console.WriteLine("StringBuilder 用时:" + watch.ElapsedMilliseconds + " ms");

进行 100000 次循环,每次进行10个字符,结果如下:

从这个结果看,String.Format 效率还是较差。

文章中部分引用自:

https://www.cnblogs.com/popzhou/p/3676691.html

C# String 字符拼接测试(“+”、string.Format、StringBuilder 比较)的更多相关文章

  1. java string字符拼接符"+"的研究

    程序: public class Test { public static void main(String args[]) { String s1 = "abc"; String ...

  2. String+ String.Concat String.Format StringBuilder 之间的性能测试

    找到一篇国外的代码,专门来测试这个, String+ String.Concat String.Format StringBuilder 前三个在100个左右字符串差不多, String.Concat ...

  3. Java String字符串/==和equals区别,str。toCharAt(),getBytes,indexOf过滤存在字符,trim()/String与StringBuffer多线程安全/StringBuilder单线程—— 14.0

    课程概要 String 字符串 String字符串常用方法 StringBuffer StringBuilder String字符串: 1.实例化String对象 直接赋值  String str=& ...

  4. Java基础(八)--String(源码)、StringBuffer、StringBuilder

    String源码:基于jdk1.8 public final class String implements Serializable, Comparable<String>, CharS ...

  5. java常用类与包装类--常用类字符串String类、StringBuffer类、Stringbuilder类

    1.String类 1.1String类的概念和储存结构: (1)字符串是一个比较特殊的对象,可以使用new,也可以不使用new来创建字符串对象 String s1 = new String(&quo ...

  6. Delphi的字符(Char),字符串(String),字符串指针(PChar),字符数组arrayofchar(来自http://delphi.cjcsoft.net/论坛)

    Delphi有三种类型的字符: AnsiChar这是标准的1字节的ANSI字符,程序员都对它比较熟悉. WideChar这是2字节的Unicode字符. Char在目前相当于AnsiChar,但在De ...

  7. Java中字符数组、String类、StringBuffer三者的相互转换

    一.StringBuffer与String的相互转换 1.将StringBuffer转换成String StringBuffer类成员toString函数可将其转换成String类型. StringB ...

  8. java实验五——字符数组、String、StringBuffer的相互转化,StringBuffer的一些方法

    package hello; import java.util.Scanner; public class 实验五 { public static void main(String[] args) { ...

  9. string与int的相互转换以及把一个字符加入到string的末尾

    #include "stdafx.h" #include<sstream> #include<string> #include<iostream> ...

随机推荐

  1. Jmeter + Ant 构建接口自动化

    1.首先安装ANT,解压,建议放根目录. 对应安装包已上传 2.环境变量配置新建 ANT_HOMEANT_HOME:解压的路径path环境配置新增Path:%ANT_HOME%\binclasspat ...

  2. alpine docker exec: "/bin/bash": stat /bin/bash: no such file or directory 解决方案

    sudo docker exec -it 1df4f9732e06 sh

  3. springboot备份mysql后发送邮件并删除备份文件,支持win和Linux

    首先加入springboot的邮箱依赖 <!--邮箱依赖--> <!-- https://mvnrepository.com/artifact/org.springframework ...

  4. python 线程队列LifoQueue-LIFO(36)

    在 python线程队列Queue-FIFO  文章中已经介绍了 先进先出队列Queue,而今天给大家介绍的是第二种:线程队列LifoQueue-LIFO,数据先进后出类型,两者有什么区别呢? 一.队 ...

  5. Qt qml的软件架构设计

    google: qt qml application architecture 有很多资源. 1 https://www.ics.com/blog/multilayered-architecture- ...

  6. P5200 [USACO19JAN]Sleepy Cow Sorting

    P5200 [USACO19JAN]Sleepy Cow Sorting 题目描述 Farmer John正在尝试将他的N头奶牛(1≤N≤10^5),方便起见编号为1…N,在她们前往牧草地吃早餐之前排 ...

  7. 5-24 c++语言之【基础知识】

    最近一段时间继续开始了c++的学习,作为c plus plus 难免会与c语言做一个对比,很明显的感受到c++语言注重代码的复用性和拓展性,而c语言更加注重其算法的高效性,这也是今后需要注意的地方,避 ...

  8. jwt 无状态分布式授权

    基于JWT(Json Web Token)的授权方式 JWT 是JSON风格轻量级的授权和身份认证规范,可实现无状态.分布式的Web应用授权: 从客户端请求服务器获取token, 用该token 去访 ...

  9. docker 宿主机与容器直接文件移动命令

    1.将容器中的文件复制到宿主机 我们把容器中的 nginx 目录整个复制到  宿主机/usr/local/nginx 目录下,使用如下命令: docker cp nginx_test: /etc/ng ...

  10. hdu 2102 a计划问题。。 双层dfs问题

    Problem Description 可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验.魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长 ...