C#入门到精通系列课程——第5章字符与字符串


◆本章简述

本章主要介绍字符和字符串,C#中用Char、String等类来表示它们。C#中对于文字的处理大多是通过对字符和字符串的操作来实现的。本章详细地介绍字符与字符串的相关内容,讲解过程中为了便于读者理解结合了大量的举例。

◆本章内容

(1)了解什么是字符类

(2)掌握如何定义及使用字符类

(3)了解什么是字符串类

(4)掌握常见的几种字符串的处理方法

(5)了解字符类与字符串类的区别

(6)了解什么是可变字符串类

(7)掌握可变字符串类的定义及使用

◆知识框架

5.1  字符类Char的使用

5.1.1  Char类概述

Char类主要用来存储单个字符,占用16位(两个字节)的内存空间。在定义字符型变量时,要以单引号表示,如‘s’表示一个字符。而"s"则表示一个字符串,虽然其只有一个字符,但由于使用双引号,所以它仍然表示字符串,而不是字符。Char的定义非常简单,可以通过下面的代码定义字符。

char ch1 = 'L';
char ch2 = '1';

注意:Char只定义一个Unicode字符。Unicode字符是目前计算机中通用的字符编码,它为针对不同语言中的每个字符设定了统一的二进制编码,用于满足跨语言、跨平台的文本转换、处理的要求。

5.1.2  Char类的使用

Char类为开发人员提供了许多的方法,可以通过这些方法灵活地操作字符。Char类的常用方法及说明如表5.1所示。

表5.1  Char类的常用方法及说明

方法

说明

IsControl

指示指定的Unicode字符是否属于控制字符类别

IsDigit

指示某个Unicode字符是否属于十进制数字类别

IsHighSurrogate

指示指定的Char对象是否为高代理项

IsLetter

指示某个Unicode字符是否属于字母类别

IsLetterOrDigit

指示某个Unicode字符是属于字母类别还是属于十进制数字类别

lsLower

指示某个Unicode字符是否属于小写字母类别

IsLowSurrogate

指示指定的Char对象是否为低代理项

IsNumber

指示某个Unicode字符是否属于数字类别

IsPunctuation

指示某个Unicode字符是否属于标点符号类别

IsSeparator

指示某个Unicode字符是否属于分隔符类别

IsSurrogate.

指示某个Unicode字符是否属于代理项字符类别

IsSurrogatePair

指示两个指定的Char对象是否形成代理项对

IsSymbol

指示某个Unicode字符是否属于符号字符类别

IsUpper

指示某个Unicode字符是否属于大写字时类别

IsWhiteSpace

指示某个Unicode字符是否属于空白类别

Parse

将指定字符串的值转换为它的等效Unicode字符

ToLower

将Unicode字符的值转换为它的小写等效项

ToLowerInvariant

使用固定区域性的大小写规则,将Unicode字符的值转换为其小写等效项

ToString

将此实例的值转换为其等效的字符串表示

ToUpper

将Unicode字符的值转换为它的大写等效项

ToUpperInvariant

使用固定区域性的大小写规则,将Unicode字符的值转换为其大写等效项

TryParse

将指定字符串的值转换为它的等效Unicode字符

可以看到Char提供了非常多的实用方法,其中以Is和To开头的比较重要。以Is开头的方法大多是判断Unicode字符是否为某个类别,以To开头的方法主要是转换为其他Unicode字符。

[例5.1]创建一个控制台应用程序,演示如何使用Char类提供的常见方法,代码如下。

static void Main(string[] args)
{
  char a = 'a';//声明字符a
  char b = '8';//声明字符b
  char c = 'L';//声明字符c
  char d = '.';//声明字符d
  char e = '|';//声明字符e
  char f = ' ';//声明字符f
  //使用IsLetter()方法判断a是否为字母
  Console.WriteLine("IsLetter()方法判断a是否为字母:{0}", Char.IsLetter(a));
  //使用IsDgit()方法判断b是否为数字
  Console.WriteLine("IsDigit()方法判断b是否为数字:{0}", Char.IsDigit(b));
  //使用IsLettrOrDigit()方法判断c是否为字母或数字
  Console.WriteLine("IsLetterOrDigit()方法判断c是否为字母或数字:{0}", Char.IsLetterOrDigit(c));
  //使用IsLower()方法判断a是否为小写字母
  Console.WriteLine("IsLower()方法判断a是否为小写字母:{0}", Char.IsLower(a));
  //使用IsUpper()方法判断c是否为大写字母
  Console.WriteLine("IsUpper()方法判断c是否为大写字母:{0}", Char.IsUpper(c));
  //使用IsPunctuation()方法判断d是否为标点符号
  Console.WriteLine("IsPunctuation()方法判断d是否为标点符号:{0}", Char.IsPunctuation(d));
  //使用IsSeparator()方法判断e是否为分隔符
  Console.WriteLine("IsSeparator()方法判断e是否为分隔符:{0}", Char.IsSeparator(e));
  //使用IsWhiteSpace()方法判断f是否为空白
  Console.WriteLine("IsWhiteSpace()方法判断f是否为空白:{0}", Char.IsWhiteSpace(f));
  Console.ReadLine();
}

程序的运行结果如图所示。

5.1.3  转义字符

转义字符是一种特殊的字符变量,其以反斜线“\”开头,后跟一个或多个字符。转义字符具有特定的含义,不同于字符原有的意义,故称“转义”。例如,定义一个字符,而这个字符是单引号,如果不使用转义字符,则会产生错误。

转义字符就相当于一个电源变换器,电源变换器就是通过一定的手段获得所需的电源形式,例如交流变为直流、高电压变为低电压、低频变为高频等。转义字符也是,它是将字符转换成另一种操作形式,或是将无法一起使用的字符进行组合。

注意:转义符“\”(单个反斜杠)只针对后面紧跟着的单个字符进行操作。

[例5.2]不使用转义字符定义字符,字符的值为单引号,产生错误,代码如下。

static void Main(string[] args)
{
    char M = ''';//声明一个字符变量,值为单引号
}

程序的运行结果如图所示。

 [例5.3]为了避免此错误,应该使用转义字符,代码如下。

static void Main(string[] args)
{
    char a = '\'';//使用转义字符定义字符的值为单引号
}

此外还有其他转义字符,如表5.2所示。

表5.2  转义字符

转义符

说明

\n

按Enter键换行

\t

横向跳到下一制表位置

\”

双引号

\b

退格

\r

按Enter键

\f

换页

\\

反斜线符

\’

单引号符

\uxxxx

4位十六进制所表示的字符,如\u0052

说明:大多数重要的正则表达式语言运算符都是非转义的单个字符。转义符“\”(单个反斜杠)通知正则表达式分析器反斜杠后面的字符不是运算符。例如,分析器将r视为字符,而将后跟r的反斜杠(\r)视为按Enter键功能。

[例5.4]创建一个控制台应用程序,然后通过转义字符使Console.Write与Console.WriteLine有相同的效果,代码如下。

static void Main(string[] args)
{
    Console.WriteLine("流浪地球");//通过Console.WriteLine输出字符串
    Console.Write("流浪地球\n");//通过使用转义字符输出字符串
    Console.Write("流浪地球\n吴京");//通过使用转义字符输出字符串
    Console.ReadLine();
}

程序的运行结果如图所示。

 说明:输出系统目录时,遇到反斜线时,使用“\\”表示,但是,如果遇到下面的情况:

Console.WriteLine("C:\\Windows\\Microsoft.Net\\Framework\\v4.0.30319\\2052");

从上面的代码看到,在有多级目录时,如果都使用“\\”,会显得非常麻烦,这时可以用一个@符号来进行多级转义,代码修改如下:

Console.WriteLine(@"C:\Windows\Microsoft.Net\Framework\v4.0.30319\2052");

闯关训练:尝试使用Char字符实现字母与ASCII的相互转换,提示:在将字母转换为ASCI时,需要使用Encoding编码类;而在将ASCII转换为字母时,直接使用Char强制类型转换即可。

5.2  字符串类String的使用

前面的章节中介绍了Char类型,它只能表示单个字符,不能表示由多个字符连接而成的字符串,在C#语言中字符串作为对象来处理,可以通过String类来创建字符串对象。可以通过相应的方法获取字符串的有效信息,如获取某字符串的长度、某个索引位置的字符等。

5.2.1  字符串的声明及赋值

在C#语言中,字符串必须包含在一对“""”(双引号)之内。例如:"23.23"、"ABCDE"、"你好"这些都是字符串常量,字符串常量是系统能够显示的任何文字信息,甚至是单个字符。

注意:在C#中由双引号("")包围的都是字符串,不能作为其他数据类型来使用,如"1+2"的输出结果永远也不会是3。

可以通过以下语法格式来声明字符串变量。

string str =[null]

string:指定该变量为字符串类型。

str:任意有效的标识符,表示字符串变量的名称。

null:如果省略null,表示str变量是未初始化的状态;否则表示声明的字符串的值就等于null

[例5.5]声明字符串变量s,实例代码如下。

string s;

说明:声明字符串变量必须经过初始化才能使用,否则编译器会报出“使用了未赋值的变量”。

声明字符串之后,需要对其进行赋值,字符串的赋值使用“=”,例如,声明一个字符串变量str,并为其赋值“C#编程词典”,代码如下。

string str = "C#编程词典";

利用字符数组初始化,示例代码如下:

char[] charArray = { 't', 'i', 'm', 'e' };
string str = new string(charArray);

提取字符数组中的一部分初始化字符串,示例代码如下:

char[] charArray = { '', '', '', '', '', '' };
string str = new string(charArray, 4, 2);

5.2.2  获取字符串长度

获取字符串的长度可以使用string类的Length属性,其语法格式如下:

public int Length { get; }

其中,属性值表示当前字符串中字符的数量。

[例5.6]定义一个字符串变量,并为其赋值,然后使用Length属性获取该字符串的长度,代码如下:

string num = "12345 67890";
int size = num.Length;

输出变量size的值,得到的结果是:11,这表示使用Length属性返回的字符串长度是包括字符串中空格的。

5.5.3  获取指定位置的字符

获取指定位置的字符可以使用string类的char简性。其语法格式如下:

public char this[int index] { get; }

◆index:当前的字符串中的位置。

◆属性值:位于index位置的字符。

[例5.7]定义一个字符串变量,并为其赋值,然后获取该字符串索引位置为5的字符并输出,代码如下:

string str = "努力工作是人生最好的投资";//创建字符车对象str
char chr = str[5];//将字符串str中索引位置为5的字符赋值给chr
Console.WriteLine("字符串中索引位置为5的字符是:" + chr);//输出chr

运行结果如下:

说明:字符串中的索引位置是从0开始的。

5.2.4  获取子字符串索引位置

string类提供了两种查找字符串索引的方法,即IndexOf()与LastIndexOf()方法。其中,IndexOf()方法返回的是搜索的字符或字符串首次出现的索引位置,而LastIndexOf()方法返回的是搜索的字符或字符串最后一次出现的索引位置,本节将分别对这两个方法进行详细讲解。

1.     IndexOf()方法

IndexOf()方法返回的是搜索的字符或字符串首次出现的索引位置,其常用的几种语法格式如下:

public int IndexOf(char value)
public int Index0f(string value)
public int Index0f(char value, int startIndex)
public int Index0f(string value, int startIndex)
public int IndexOf(char value, int startIndex, int count)
public int Indexof(string value, int startIndex, int count)

value:要搜索的字符或字符串。

startIndex:搜索起始位置。

count:要检查的字符位置数。

返回值:如果找到字符或字符串,则为value的从零开始的索引位置;如果未找到字符或字符串,则为-1。

[例5.8]查找字符e在字符串str中第一次出现的索引位置,代码如下:

string str = "We are the world";
int size = str.IndexOf('e');//size的值为1

理解字符串的索引位置,需要对字符串的下标有所了解。在计算机中,string对象是用数组表示的。字符串的下标是0~Length-1。上面代码中的字符串str的下标排列如图所示。

多学两招:在日常开发工作中,经常会遇到判断一个字符串中是否包含某个字符或者某个子字符串的情况,这时就可以使用IndexOf()方法。

[例5.9]查找字符串“We are the world”中“r”第一、二、三次出现的索引位置,代码如下:

static void Main(string[] args)
{
    string str = "We are the world";//创建字符串
    int firstIndex = str.IndexOf("r");//获取字符串中“r”第一次出现的索引位置
    //获取字符串中“r”第二次出现的索引位置,从第一次出现的索引位置之后开始查找
    int secondIndex = str.IndexOf("r", firstIndex + 1);
    //获取字符串中“r”第三次出现的索引位置,从第二次出现的素引位置之后开始查找
    int thirdIndex = str.IndexOf("r", secondIndex + 1);
    //输出三次获取的索引位置
    Console.WriteLine("r第一次出现的索引位置是:" + firstIndex);
    Console.WriteLine("r第二次出现的素引位置是:" + secondIndex);
    Console.WriteLine("r第三次出现的索引位置是:" + thirdIndex);
    Console.ReadLine();
}

程序运行结果如图所示。

从图中可以看出,由于字符串中只有两个“r”,所以程序输出了这两个“r”的索引位置,第三次搜索时已经找不到“r”了,所以返回-1。

拓展训练:

一、定义一个字符串“世界上最快乐的事,莫过于为理想而奋斗!”,然后确认该字符串中是否存在关键字“理想”。

二、有一个书单“零基础学C#、C#从入门到精通、C#项目开发实战入门”,请编程实现,查询“零基础学C#”在该书单中的位置。

2.  LastIndexOf()方法

LastIndexOf()方法返回的是搜索的字符或字符串最后一次出现的索引位置,其常用的几种语法格式如下:

public int LastIndexOf(char value)
public int LastIndexOf(string value)
public int LastIndex0f(char value, int startIndex)
public int LastIndexOf(string value, int startIndex)
public int LastIndexOf(char value, int startIndex, int count)
public int LastIndexOf(string value, int startIndex, int count)

value:要搜索的字符或字符串。

startIndex:搜索起始位置。

count:要检查的字符位置数。

返回值:如果找到字符或字符串,则为value的从零开始的索引位置;如果未找到字符或字符串,则为-1。

[例5.10]查找字符e在字符串str中最后一次出现的索引位置,代码如下:

string str = "We are the world";
int size = str.LastIndexOf('e'); //size的值为9

字符e在字符串str中最后一次出现的索引位置如图所示。

5.2.5  判断字符串首尾内容

string类提供了两种判断字符串首尾内容的方法,即StartsWith()与EndsWith()方法。其中,StartsWith()方法用来判断字符串是否以指定的内容开始,而EndsWith()方法用来判断字符串是否以指定的内容结束,本节将分别对这两个方法进行详细讲解。

1.  StartsWith()方法

StartsWith()方法用来判断字符串是否以指定的内容开始,其常用的几种语法格式如下:

public bool StartsWith(string value)
public bool StartsWith(string value, bool ignoreCase, CultureInfo culture)

value:要比较的字符串。

ignoreCase:在比较过程中如果忽略大小写,则为true;否则为false。

culture:CultureInfo对象,用来确定如何对字符串与value进行比较的区域性信息。如果culture为null,则使用当前区域性。

返回值:如果value与字符串的开头匹配,则为true;否则为false。

[例5.11]使用StartsWith方法判断一个字符串是否以“梦想"开始,代码如下:

static void Main(string[] args)
{
  string str = "梦想还是要有的,万一实现了呢!";//定义一个字符串,并初始化
  bool result = str.StartsWith("梦想");//判断str是否以“梦想”开始
  Console.WriteLine(result);
}

上面代码的运行结果为:

 多学两招:如果在判断某一个英文字符串是否以某字母开始时,需要忽略大小写,可以使用第2种形式,并将第2个参数设置为true。例如,定义一个字符串“Keep on going never give up”,然后使用StartsWith方法判断该字符串是否以"keep"开始,代码如下:

static void Main(string[] args)
{
  string str = "Keep on going never give up";
  bool result = str.StartsWith("keep", true, null);//判断str是否以keep开始
  Console.WriteLine(result);
}

上面代码的返回结果为True,因为这里使用了StartsWith方法的第2种形式,并且第2个参数为true,在比较时,会忽略“Keep”和“keep”大小写,因此返回结果为

2.  EndsWith()方法

EndsWith()方法用来判断字符串是否以指定的内容结束,其常用的几种语法格式如下:

public bool EndsWith(string value)
public bool EndsWith(string value, bool ignoreCase, CultureInfo culture)

value:要比较的字符串。

ignoreCase:要在比较过程中忽略大小写,则为true;否则为false。

culture:Culturelnfo对象,用来确定如何对字符串与value进行比较的区域性信息。如果culture为null,则使用当前区域性。

返回值:如果value与字符串的末尾匹配,则为true;否则为false。

多学两招:如果在比较时需要忽略大小写,通常使用第2种形式,并将第2个参数设置为true。

[例5.12]使用EndsWith方法判断一个字符串是否以句号(。)结束,代码如下:

static void Main(string[] args)
{
  string str = "梦想还是要有的,万实现了呢!";//定义一个字符串,并初始化
  bool result = str.EndsWith("");//判断str是否以“。”结尾
  Console.WriteLine(result);
}

上面代码的运行结果为

5.2.6  连接多个字符串

使用“+”运算符可完成对多个字符串连接的功能。“+”运算符可以连接多个字符串并产生一个String对象。

[例5.13]定义两个字符串,使用“+”运算符连接,代码如下。

static void Main(string[] args)
{
  string s1 = "hello";//声明String对象s1
  string s2 = "world";//声明String对象s2
  string s = s1 + " " + s2;//将对象s1和s2连接后的结果赋值给s
}

注意:C#中一句相连的字符串不能分开在两行中写。例如:

Console.WriteLine("I like
C#")

这种写法是错误的,如果一个字符串太长,为了便于阅读,可以将这个字符串分在两行上书写。此时就可以使用“+”将两个字符串连起来,之后在加号处换行。因此,上面的语句可以修改为:

Console.WriteLine("I like" +
"C#");

5.2.7  比较字符串

对字符串值进行比较时,可以使用前面学过的比较运算符“==”实现。

[例5.14]使用比较运算符比较两个字符串的值是否相等,实例代码如下。

static void Main(string[] args)
{
  string str1 = "mingrikeji";
  string str2 = "mingrikeji";
  Console.WriteLine((str1 == str2));
}

此时,输出结果为

除了使用比较运算符“==”,在C#中最常见的比较字符串的方法还有Compare()、CompareTo()和Equals()方法等,这些方法都归属于String类。下面对这3种方法进行详细的介绍。

1.  Compare()方法

Compare()方法用来比较两个字符串是否相等,它有很多个重载方法,其中最常用的两种方法如下。

Int Compare(string strA, string strB)
Int Compare(string strA, string strB, bool ignorCase)

strA和strB:代表要比较的两个字符串。

ignorCase:是一个布尔类型的参数,如果这个参数的值是true,那么在比较字符串时就忽略大小写的差别。Compare()方法是一个静态方法,所以在使用时,可以直接引用。

[例5.15]创建一个控制台应用程序,声明两个字符串变量,然后使用Compare()方法比较两个字符串是否相等,代码如下。

static void Main(string[] args)
{
  string Str1 = "华为P30";//声明一个字符串Str1
  string Str2 = "华为P30Pro";//声明一个字符串Str2
  Console.WriteLine(string.Compare(Str1, Str2));//输出字符串Str1与Str2比较后的返回值
  Console.WriteLine(string.Compare(Str1, Str1));//输出字符串Str1与Str1比较后的返回值
  Console.WriteLine(string.Compare(Str2, Str1));//输出字符串Str2与Str1比较后的返回值
  Console.ReadLine();
}

程序的运行结果为:

注意:比较字符串并非比较字符串长度的大小,而是比较字符串在英文字典中的位置。比较字符串按照字典排序的规则,判断两个字符串的大小。在英文字典中,前面的单词小于在后面的单词。

2.  CompareTo()方法

CompareTo()方法与Compare()方法相似,都可以比较两个字符串是否相等,不同的是CompareTo()方法以实例对象本身与指定的字符串作比较,其语法如下。

public int CompareTo(string strB)

[例5.16]对字符串stra和字符串strb进行比较,代码如下。

stra.CompareTo(strb);

如果stra的值与strb的值相等,则返回0;如果stra大于strb的值,则返回1;否则返回-1。

[例5.17]创建一个控制台应用程序,使用CompareTo()方法比较两个字符串,代码如下。

static void Main(string[] args)
{
  string Str1 = "支付宝";//声明-个字符串Str1
  string Str2 = "微信支付";//声明-一个字符串Str2
  Console.WriteLine(Str1.CompareTo(Str2));//输出Str1与Str2比较后的返回值
  Console.ReadLine();
}

由于字符串Str1在字典中的位置比字符串Str2的位置靠后,所以运行结果为

3.  Equals()方法

Equals()方法主要用于比较两个字符串是否相同,如果相同返回值是true;否则为flse,其常用的两种方式的语法如下。

public bool Equals(string value)
public static bool Equals(string a, sting b)

value:是与实例比较的字符串。

a和b:是要进行比较的两个字符串。

[例5.18]创建一个控制台应用程序,声明两个字符串变量,然后使用Equls()方法比较两个字符串是否相同,代码如下。

static void Main(string[] args)
{
  string Str1 = "支付宝";//声明一个字符串Str1
  string Str2 = "微信支付";//声明一个字符串Str2
  Console.WriteLine(Str1.Equals(Str2));//用Equals()方法比较字符串Str1和Str2
  Console.WriteLine(string.Equals(Str1, Str2));//用Equals()方法比较字符串Str1和Str2
  Console.ReadLine();
}

程序的运行结果为:

说明:Equals()方法执行顺序(区分大小写和区域性)比较。

5.2.8  字符串的大小写转换

对字符串进行大小写转换时,需要使用string类提供的ToUpper()方法和ToLower()方法,其中,ToUpper()方法用来将字符串转换为大写形式,而ToLower()方法用来将字符串转换为小写形式,它们的语法格式如下:

public string ToUpper()
public string ToLower()

说明:如果字符串中没有需要被转换的字符(比如数字或者汉字),则返回原字符串。

[例5.19]定义一个字符串,赋值为“Learn and live”,分别用大写、小写两种格式输出该字符串,代码如下:

static void Main(string[] args)
{
  string str = "Learn and 1ive";
  Console.WriteLine(str.ToUpper());//大写输出
  Console.WriteLine(str.ToLower());//小写输出
}

运行结果为:

多学两招:在各种网站的登录页面中,验证码的输入通常都是不区分大小写的,这样的情况,就可以使用ToUpper()或者ToLower()方法将网页显示的验证码和用户输入的验证码同时转换为大写或者小写,以方便验证。

5.2.9  格式化字符串

在C#中,String类提供了一个静态的Format()方法,用于将字符串数据格式化成指定的格式,其语法格式如下。

public static string Format(string format, object obj);
public static string Format(string format, params object[] objs);

format:用来指定字符串所要格式化的形式,该参数的基本格式如下:

{index[,length][:formatString]}

index:要设置格式的对象的参数列表中的位置(从零开始)。

length:参数的字符串表示形式中包含的最小字符数。如果该值是正的,则参数右对齐;如果该值是负的,则参数左对齐。

formatString:要设置格式的对象支持的标准或自定义格式字符串。

obj:要被格式化的对象。

objs:一个对象数组,其中包含零个或多个要设置格式的对象。

说明:format参数由零或多个文本序列与零或多个索引占位符混合组成,其中索引占位符称为格式项,它们与此方法的参数列表中的对象相对应。格式设置过程将每个格式项替换为相应对象值的文本表示形式。格式项的语法是{索引[,对齐方式][:格式字符串]},它指定了一个强制索引、格式化文本的可选长度和对齐方式,以及格式说明符字符的可选字符串,其中格式说明符字符用于控制如何设置相应对象的值的格式。

[例5.20]创建一个控制台应用程序,声明两个string类型的变量StrA和StrB,然后使用Format()方法格式化这两个string类型变量,最后输出格式化后的字符串,代码如下。

static void Main(string[] args)
{
  string StrA = "相信自己";//声明字符串StrA
  string StrB = "永不放弃";//声明字符串StrB
  string newstr = string.Format("{0},{1}!!!", StrA, StrB);//格式化字符串
  Console.WriteLine(newstr);//输出结果
  Console.ReadLine();
}

程序的运行结果为

格式化字符串主要有两种情况,分别是数值类型数据的格式化和日期时间类型数据的格式化,下面分别讲解。

1.  数值类型数据的格式化

在实际开发中,数值类型有多种显示方式,比如货币形式、百分比形式等,C#支持的标准数值格式规范如表5.3所示。

表5.3  C#支持的标准数值格式规范

格式说明符

名称

说明

示例

C或c

货币

结果:货币值

受以下类型支持:所有数值类型

精度说明符:小数位数

¥123或-¥123.456

D或d

Decimal

结果:整型数字,负号可选

受以下类型支持:仅整型

精度说明符:最小位数

1234或-001234

E或e

指数(科学型)

结果:指数记数法

受以下类型支持:所有数值类型

精度说明符:小数位数

1.052033E+003

或-1.05e+003

F或f

定点

结果:整数和小数,负号可选

受以下类型支持:所有数值类型

精度说明符:小数位数

1234.57或-1234.5600

N或n

Number

结果:整数和小数、组分隔符和小数分隔符,负号可选

受以下类型支持:所有数值类型

精度说明符:所需的小数位数

1,234.57或-1,234.560

P或p

百分比

结果:乘以100并显示百分比符号的数字

受以下类型支持:所有数值类型

精度说明符:所需的小数位数

100.00%或100%

X或x

十六进制

结果:十六进制字符串

受以下类型支持:仅整型

精度说明符:结果字符串中的位数

FF或O0ff

注意:使用sring.Format方法对数值类型数据格式化时,传入的参数必须为数值类型。

[例5.21]使用表5.3中的标准数值格式规范对不同的数值类型数据进行格式化,并输出,代码如下:

static void Main(string[] args)
{
  //输出金额
  Console.WriteLine(string.Format("1251+3950的结果是(以货币形式显示):{0:C}", 1251 + 3950));
  //输出科学计数法
  Console.WriteLine(string.Format("120000.1用科学计数法表示:{0:E}", 120000.1));
  //输出以分隔符显示的数字
  Console.WriteLine(string.Format("12800以分隔符数字显示的结果是:{0:N0}", 12800));
  //输出小数点后两位
  Console.WriteLine(string.Format("π取两位小数点:{0:F2}", Math.PI));
  //输出十六进制
  Console.WriteLine(string.Format("33的16进制结果是:{0:x4}", 33));
  //输出百分号数字
  Console.WriteLine(string.Format("天才是由{0:P0}的灵感,加上{1:P0}的汗水。", 0.01, 0.99));
  Console.ReadLine();
}

程序运行结果如图所示。

拓展训练:

一、在控制台中显示3种商品,分别为“1、iPhone6(16G)5288”“2、荣耀6 Plus(高配版)2999”和“3、一加手机(标准版)1999.99”,然后根据用户输入的编号,提示用户购买的商品及价格,其中价格以货币形式显示。

二、模拟微信抢红包(提示:本实例实现时用到了Random类,该类用来生成随机数),运行效果如图所示。

2.  日期时间类型数据的格式化

如果希望日期时间按照某种标准格式输出。比如短日期格式、完整日期时间格式等,那么可以使用string类的Format方法将日期时间格式化为指定的格式。C#支持的日期时间类型格式规范如表5.4所示。

表5.4  C#支持的日期时间类型格式规范

格式规范

说明

短日期格式(YYYY-MM-dd)

长日期格式(YYYY年MM月dd日)

短时间格式(hh:mm)

长时间格式(hh:mm:ss)

完整日期/时间格式(短时间)(YYYY年MM月dd日 hh:mm)

完整日期/时间格式(长时间)(YYYY年MM月dd日 hh:mm:ss)

常规日期/时间格式(短时间)(YYYY-MM-dd hh:mm)

常规日期/时间格式(长时间)(YYYY-MM-dd hh:mm:ss)

M或m

月/日格式(MM月dd日)

Y或y

年/月格式(YYYY年MM月)

注意:使用string.Formnat方法对日期时间类型数据格式化时,传入的参数必须为DateTime类型。

[例5.22]使用表5.4中的标准日期时间格式规范对不同的日期时间数据进行格式化,并输出,代码如下:

static void Main(string[] args)
{
  DateTime strDate = DateTime.Now;//获取当前日期时间
  //输出短日期格式
  Console.WriteLine(string.Format("当前日期的短日期格式表示:{0:d}", strDate));
  //输出长日期格式
  Console.WriteLine(string.Format("当前日期的长日期格式表示:{0:D}", strDate));
  Console.WriteLine();//换行
  //输出完整日期/时间格式(短时间)
  Console.WriteLine(string.Format("当前日期时间的完整日期时间格式(短时间)表示:{0:f}", strDate));
  //输出完整日期/时间格式(长时间)
  Console.WriteLine(string.Format("当前日期时间的完整日期/时间格式(长时间)表示:{0:F}", strDate));
  Console.WriteLine();//换行
  //输出常规日期/时间格式(短时间)
  Console.WriteLine(string.Format("当前日期时间的常规日期/时间格式(短时间)表示:{0:g}", strDate));
  //输出常规日期/时间格式(长时间)
  Console.WriteLine(string.Format("当前日期时间的常规日期时间格式(长时间)表示:{0:G}", strDate));
  Console.WriteLine();//换行
  //输出时间格式
  Console.WriteLine(string.Format("当前时间的短时间格式表示:{0:t}", strDate));
  //输出长时间格式
  Console.WriteLine(string.Format("当前时间的长时间格式表示:{0:T}", strDate));
  Console.WriteLine();//换行
  //输出月/日格式
  Console.WriteLine(string.Format("当前日期的月/日格式表示:{0:M}", strDate));
  //输出年/月格式
  Console.WriteLine(string.Format("当前日期的年/月格式表示:{0:Y}", strDate));
  Console.ReadLine();
}

说明:代码中获取当前时间时用到了DateTime结构,该结构是.NET Framework自带的,表示时间上的一刻,通常以日期和当天的时间表示。DateTime.Now用来获取计算机上的当前日期和时间。

程序运行结果如图所示。

拓展训练:

一、在控制台中输出一天的天气预报及主要时刻点的天气情况,其输出信息如下:

 二、模拟输出员工的打卡时间(例如,员工名为mr),输出形式如下:

 多学两招:通过在ToString方法中传入指定的“格式说明符”,也可以实现对教值型数据和日期时间型数据的格式化,例如,下面的代码分别使用ToString方法将数字1298格式化为货币形式、当前日期格式化为年/月格式,代码如下:

int money = 1298;
Console.WriteLine(money.ToString("C"));//使用ToString方法格式化数值类型
DateTime dTime = DateTime.Now;
Console.WriteLine(dTime.ToString("Y"));//使用ToString方法格式化日期时间类型

互动练习:尝试使用C#制作一个商品金额大小写转换的程序,具体要求为:在一个文本框中输入小写的金额,单击“转换”按钮,自动转换为大写的金额表示方法。

5.2.10  截取字符串

String类提供了一个Substring()方法,该方法可以截取字符串中指定位置和指定长度的子字符串,该方法有两种使用形式,其语法格式如下。

public string Substring(int startIndex)
public string Substring(int startIndex, int length)

startIndex:子字符串的起始位置的索引。

Length:子字符串中的字符数。

[例5.22]创建一个控制台应用程序,声明两个string类型的变量StrA和StrB,并将StrA初始化为“今天你消耗了多少卡路里”,然后使用Substring()方法从索引2开始截取4个字符,赋值给StrB,并输出StrB,代码如下。

static void Main(string[] args)
{
  string StrA = "今天你消耗了多少卡路里";//声明字符串StrA
  string StrB = "";//声明字符串StrB
  StrB = StrA.Substring(2, 4);//截取字符串
  Console.WriteLine(StrB);//输出截取后的字符串
  Console.ReadLine();
}

程序的运行结果为

说明:在用Substring()方法截取字符串时,如果length参数的长度大于截取字符串的长度,将从起始位置的索引处截取之后的所有字符。

闯关训练:从一个全路径的字符串中分离出文件路径、文件名及扩展名等信息。

拓展训练:

一、根据输入的身份证号获取生日信息。

二、将“津A·12345”“沪A·23456”“京A·34567”这三张号牌放到string类型的数组中,然后在遍历数组的过程中完成对每张号牌归属地的判断。效果如图所示。

5.2.11  分割字符串

String类提供了一个Split()方法,用于根据指定的字符数组或者字符串数组对字符串进行分割,此方法的返回值是包含所有分割子字符串的数组对象,可以通过数组取得所有分割的子字符串,该方法有5种使用形式,其语法格式如下。

public string[] Split(params char[] separator)
public string[] Split(char[] separator, int count)
public string[] Split(string[] separator, StringSplitOptions options)
public string[] Split(char[] separator, int count, StringSplitOptions options)
public string[] Spllt(string[] separator, int count, StringSplitOptions options)

separator:分隔字符串的字符数组或字符串数组。

count:要返回的子字符串的最大数量。

options:要省略返回的数组中的空数组元素,则为RemoveEmptyEntries;要包含返回的数组中的空数组元素,则为None。

[例5.23]创建一个控制台应用程序,声明一个string类型变量StrA,初始化为“AI时代已经到来,你还在等什么”,然后通过Split()方法分割变量StrA,并输出分割后的字符串,代码如下。

static void Main(string[] args)
{
  string StrA = "AI时代已经到来,你还在等什么";//声明字符串StrA
  char[] separator = {''};//声明分割字符的数组
  string[] splitstrings = new string[100];//声明一个字符串数组
  splitstrings = StrA.Split(separator);//分割字符串
  for (int i = 0; i < splitstrings.Length; i++)
  {
    Console.WriteLine("item{0}:{1}", i, splitstrings[i]);
  }
  Console.ReadLine();
}

程序的运行结果为:

拓展训练:

一、根据“。”符号对长段的文本进行分段显示,长段文本可以自己手动输入。

二、平时在使用邮箱发送邮件时,可以同时给多人发送邮件,现在要求使用C#模拟实现邮件的发送功能,具体要求为:输入多个收件人,邮件主题及内容,然后按键盘上的键,显示邮件发送成功的信息提示,同时显示收件人列表、邮件的主题、内容及邮件的发送时间,运行结果如图所示。

5.2.12  去除空白内容

string类提供了一个Trim方法,用来移除字符串中的所有开头空白字符和结尾空白字符,其语法格式如下:

public string Trim()

Trim方法的返回值是从当前字符串的开头和结尾删除所有空白字符后剩余的字符串。

[例5.24]定义一个字符串strOld,并初始化为“     abe     ”,然后使用Trim方法删除该字符串中开头和结尾处的所有空白字符,代码如下:

static void Main(string[] args)
{
  string str = "     abc     ";//定义原始字符串
  string shortStr = str.Trim();//去掉字符串的首尾空格
  Console.WriteLine("str的原值是:[" + str + "]");
  Console.WriteLine("去掉首尾空白的值:[" + shortStr + "]");
}

上面代码的运行结果如下:

 多学两招:使用Trim方法还可以从字符串的开头和结尾删除指定的字符,它的使用形式如下:

public string Trim(params char[] trimChars)

[例5.25]使用Trim方法删除字符串开头和结尾处的“*”字符,代码如下:

Char[] charsToTrim = { '*' };//定义要删除的字符数组
string str = "*****abc*****";//定义原始字符串
string shortStr = str.Trim(charsToTrim);//去掉字符串的首尾空格

5.2.13  插入和填充字符串

1.  插入字符串

String类提供了一个Insert()方法,用于向字符串的任意位置插入新元素,其语法格式如下。

public string Insert(int startIndex, string value);

startIndex:用于指定所要插入的位置,索引从0开始。

value:指定所要插入的字符串。

[例5.26]创建一个控制台应用程序,声明3个string类型的变量strl、st2和str3。将变量strl初始化为“梦想还是要有的,万一实现了呢!”。然后使用Insert()方法在字符串strl的索引0处插入手符串“马云说:”,并赋给字符串str2。最后在字符串str2的索引19处插入字符串“你信吗",赋给字符串str3,并输出str3,代码如下。

static void Main(string[] args)
{
  string str1 = "梦想还是要有的,万一实现了呢!";//声明字符串变量str1井赋值
  string str2;//声明字符串变量str2
  str2 = str1.Insert(0, "马云说:");//使用Insert()方法向字符串str1中插入字符串
  string str3 = str2.Insert(19, "你信吗");//使用Insert()方法向字符串str2中插入字符串
  Console.WriteLine(str3);//输出字符串变量str3
  Console.ReadLine();
}

程序的运行结果为

说明:如果想要在字符串的尾部插入字符串,可以用字符串变量的Length属性来设置插入的起始位置。

2.  填充字符串

String类提供了PadLeft()/PadRight()方法用于填充字符串,PadLeft()方法在字符串的左侧进行字符填充,而PadRight()方法在字符串的右侧进行字符填充。PadLeft()方法的语法格式如下。

public string PadLeft(int totalWidth, char paddingChar)

PadRight()方法的语法格式如下。

public string PadRight(int totalWidth, char paddingChar)

totalWidth:指定填充后的字符串长度。

paddingChar:指定所要填充的字符,如果省略,则填充空格符号。

[例5.27]创建一个控制台应用程序,声明3个string类型的变量strl、str2和str3。将str1初始化为“*^__^*”.然后使用PadLeft()方法在strl的左侧填充字符“(”,并赋给字符串str2。最后使用PadRight()方法在字符串str2的右侧填充字符“)”,得到字符串“(*^__^*)",赋给字符串str3,并输出字符串str3,代码如下。

static void Main(string[] args)
{
  string str1 = "*^__^*";//声明一个字符串变量str1
  //声明一个字符串变量str2,井使用PadLeft()方法在str1的左侧填充字符“(”
  string str2 = str1.PadLeft(7, '(');
  //声明一个字符串变量str3,并使用PadRight()方法在str2右侧填充字符“)”
  string str3 = str2.PadRight(8, ')');
  Console.WriteLine("补充字符串之前:" + str1);//输出字符串str1
  Console.WriteLine("补充字符串之后:" + str3);//输出字符串str3
  Console.ReadLine();
}

程序的运行结果为:

5.2.14  删除字符串

String类提供了一个Remove()方法,用于从一个字符串的指定位置开始,删除指定数量的字符,其语法格式如下。

public String Remove(int startIndex);
public String Remove(int startIndex, int count);

startIndex:用于指定开始删除的位置,索引从0开始。

count:指定删除的字符数量。

注意:参数count的值不能为0或是负数(startIndex参数也不能为负数),如果为负数,将会引发ArgumentOutOfRangeException异常(当参数值超出调用的方法所定义的允许取值范围时引发的异常);如果为0,则删除无意义,也就是没有进行删除。

Remove()方法有两种语法格式,第一种格式删除字符串中从指定位置到最后位置的所有字符;第二种格式从字符串中指定位置开始删除指定数目的字符。

[例5.28]创建一个控制台应用程序,声明一个string类型的变量strl,并初始化为“.NET也开源了!",然后使用Remove()方法的第一种语法格式删除索引4后面的所有字符,代码如下。

static void Main(string[] args)
{
  string str1 = ".NET也开源了!";//声明一个字符串变量str1
  //声明一个字符串变量str2,并使用Remove()方法从字符串str1的索引4处开始删除
  string str2 = str1.Remove(4);
  Console.WriteLine(str2);//输出字符串str2
  Console.ReadLine();
}

程序的运行结果为

下面再通过实例演示如何使用Remove()方法的第二种语法格式。

[例5.29]创建一个控制台应用程序,声明一个string类型变量strl,并初始化为“NET也开源了!",然后使用Remove()方法的第二种语法格式从索引位置0开始,删除4个字符,代码如下。

static void Main(string[] args)
{
  string str1 = ".NET也开源了!";//声明一个字符串变量str1,井初始化
  //声明一个字符串变量str2,并使用Remove()方法从字符串str1的索引0处开始删除4个字符
  string str2 = str1.Remove(0, 4);
  Console.WriteLine(str2);//输出字符串str2
  Console.ReadLine();
}

程序的运行结果为

5.2.15  复制字符串

String类提供了Copy()和CopyTo()方法,用于将字符串或子字符串复制到另一个字符串或Char类型的数组中。

1.  Copy()方法

创建一个与指定的字符串具有相同值的字符串的新实例,其语法格式如下。

public static string Copy(string str)

str:是要复制的字符串。

返回值:与str具有相同值的字符串。

[例5.30]创建一个控制台应用程序,声明一个string类型的变量stra,并初始化为“AI时代”,然后使用Copy()方法复制字符串stra,并赋给字符串strb,代码如下。

static void Main(string[] args)
{
  string stra = "Al时代";//声明一个字符串变量stra并初始化
  string strb;//声明一个字符串变量strb
  //使用String类的Copy()方法,复制字符串stra井赋值给strb
  strb = String.Copy(stra);
  Console.WriteLine(strb);//输出字符串strb
  Console.ReadLine();
}

程序的运行结果为

2.  CopyTo()方法

CopyTo()方法的功能与Copy()方法基本相同,但是CopyTo()方法可以将字符串的某一部分复制到另一个数组中,其语法格式如下。

public void CopyTo(int sourceIndex,char[] destination,int destinationIndex, int count);

CopyTo()方法的参数及说明如表5.5所示。

表5.5  CopyTo()方法的参数及说明

参数

说明

sourceIndex

需要复制的字符的起始位置

destination

目标字符数组

destinationIndex

指定目标数组中的开始存放位置

count

指定要复制的字符个数

注意:当参数sourceIndex、destinationIndex或count为负数,或者参数count大于从startIndex到此实例末尾的子字符串的长度,或者参数count大于从destinationIndex到destination末尾的子数组的长度时,则引发ArgumentOutOfRangeException异常(当参数值超出调用的方法所定义的允许取值范

围时引发的异常)。

下面通过实例演示如何使用CopyTo()方法。

[例5.31]创建一个控制台应用程序,声明一个string类型变量str1,并初始化为“机器学习及深度学习”。然后声明一个char类型的数组str使用CopyTo()方法将“机器学习”复制到数组str中,代码如下。

static void Main(string[] args)
{
  string str1 = "机器学习及深度学习";//声明一个字符串变量str1井初始化
  char[] str = new char[100];//声明一个字符数组str
  //将字符串str1从索引0开始的4个字符复制到字符数组str中
  str1.CopyTo(0, str, 0, 4);
  Console.WriteLine(str);//输出字符数组中的内容
  Console.ReadLine();
}

程序的运行结果为

5.2.16  替换字符串

String类提供了一个Replace()方法,用于将字符串中的某个字符或字符串替换成其他的字符或字符串,其语法格式如下。

public string Replace(char OChar, char NChar)
public string Replace(string OValue, string NValue)

Replace()方法的参数及说明如表5.6所示。

表5.6  Replace()方法的参数及说明

参数

说明

OChar

待替换的字符

NChar

替换后的新字符

OValue

待替换的字符串

NValue

替换后的新字符串

上述Replace()方法有两种语法格式:第一种语法格式主要用于替换字符串中指定的字符;第二种语法格式主要用于替换字符串中指定的字符串,下面通过实例演示这两种语法格式的用法。

[例5.32]创建一个控制台应用程序,声明一个string类型变量strOld,并初始化为“one world,one dream”。然后使用Replace方法的第一种语法格式将字符串中的“,”替换成“*”,最后使用Replace方法的第二种语法格式将字符串中的“one”普换成“One”,代码如下:

static void Main(string[] args)
{
  string strOld = "one world,one dream";//声明一个字符串变量并初始化
  Console.WriteLine("原始字符串:" + strOld);//输出原始字符串
  string strNew1 = strOld.Replace('', '*');//使用Replace将字符串中的“,”替换为“*”
  Console.WriteLine("\n第一种形式的替换:" + strNew1);
  //使用Replace方法将字符串中的“one”替换为“One”
  string strNew2 = strOld.Replace("one", "One");
  Console.WriteLine("\n第二种形式的替换:" + strNew2);
  Console.ReadLine();
}

程序运行结果如图所示。

说明:如果要替换的字符或字符串在原字符串中重复出现多次,Replace方法会将所有的都进行替换。

注意:要替换的字符或字符串的大小写需要与原字符串中字符或字符串的大小写保持一致,否则不能成功地替换。例如,如果将上面的代码修改成如下代码,则不能成功替换。

string strOld = "one world,one dream";//声明一个字符串变量并初始化
string strNew2 = strOld.Replace("ONE", "One");//字符串替换

拓展训练:

一、模拟实现Word的全部替换功能。

二、马云的成功秘诀是:永不抱怨!现在通过程序把这个秘诀复制到我们每个人身上,输出“我们的成功秘诀:永不抱怨!”。

互动练习:尝试使用C#制作一个对字符串进行加密与解密的程序,主要调用已有类库中的ToEncrypt()方法和ToDecrypt()方法实现。

5.2.17  字符串插值

C#的一项新功能是字符串插值,有了它就基本上不用“+”操作符连接字符串了。连接字符串通常是为了生成插入变量值的字符串。

例如,下列代码:

int num = 123;
Console.WriteLine("num的值是:" + num);

字符串插值则允许这样写:

Console.WriteLine($"num的值是:{num}");

开头的“$”符号表明这是插值字符串,“{”和“}”之间的任何表达式都要求值并置换。无前置“$”符号,字符串“{num}”将按字面处理。

字符串插值比“+”操作符高效得多。由于.NET Framework处理字符串的方式,用“+”来连接字符串可能消耗大量内存。字符串插值还更具可读性和减少犯错机会(虽然这一点有争议)。

5.3  可变字符串类

对于创建成功的字符串对象,它的长度是固定的,内容不能被改变和编译。虽然使用“+”可以达到附加新字符或字符串的目的,但“+”会产生一个新的String实例,会在内存中创建新的字符串对象。如果重复地对字符串进行修改,将极大地增加系统开销。而C#中提供了一个可变的字符序列StringBuilder类,大大提高了频繁增加字符串的效率。本节将对其使用进行讲解。

5.3.1  StringBuilder类的定义

StringBuilder类有6种不同的构造方法,其语法格式如下。

public StringBuilder()
public StringBuilder(int capacity)
public StringBuilder(string value)
public StringBuilder(int capacity, int maxCapacity)
public StringBuilder(string value, int capacity)
public StringBuilder(string value, int startIndex, int length, int capacity)

capacity:StringBuider对象的建议起始大小。

value:字符串,包含用于初始化StringBuilder对象的子字符串。

maxCapacity:当前字符串可包含的最大字符数。

startIndex:value中子字符串开始的位置。

length:子字符串中的字符数。

[例5.33]创建一个StringBuilder对象,其初始引用的字符串为“Hello World!",代码如下。

StringBuilder MySringBuilder = new StringBuilder("Hello Word!");

说明:StringBuilder类表示值为可变字符序列的类似字符串的对象,之所以说值是可变的,是因为在通过追加、移除、替换或插入字符而创建它后可以对它进行修改。

5.3.2  StringBuilder类的使用

SringBuilder类存在于System.Text命名空间中,如果要创建StingBuiderr对象,首先必须引用此命名空间。StringBuilder类中常用的方法及说明如表5.7所示。

表5.7  StringBuilder类中常用的方法及说明

方法

说明

Append

将文术或字符串迫加到指定对象的末尾

AppendFormat

自定义变量的格式并将这些值追加到StringBuilder对象的末尾

Insert

将字符串或对象添加到当前StringBuilder对象中的指定位置

Remove

从当前StringBuilder对象中移除指定数量的字符

Replace

用另一个指定的字符来替换StringBuilder对象内的字符

说明:StringBuilder类提供的方法都有多种使用形式,开发者可以根据需要选择合适的使用形式。

下面通过实例来演示如何使用StringBuilder类中的这5种方法。

[例5.34]创建一个控制台应用程序,声明一个int类型的变量Num,并初始化为1000然后创建一个StringBuilder对象,并初始化,初始大小为100。最后使用StringBuilder类的Append()、AppendFormat()、Insert()、Remove()和Replace()方法操作StringBuilder对象,代码如下。

static void Main(string[] args)
{
  int Num = 1000;//声明一个int类型变量Num并初始化为1000
  //实例化一个StringBuilder类,井初始化为“荣耀自称科技标杆”
  StringBuilder honorvsxiaomi = new StringBuilder("荣耀自称科技标杆", 100);
  //使用Append()方法将字符串追加到honorvsxiaomi的末尾
  honorvsxiaomi.Append("VS 小米死磕高性价比");
  Console.WriteLine(honorvsxiaomi);//输出honorvsxiaomi
  //使用AppendFormat()方法将字符串按照指定的格式追加到honorvsxiaomi的末尾
  honorvsxiaomi.AppendFormat("{0:C}", Num);
  Console.WriteLine(honorvsxiaomi);
  //使用Insert()方法将“PK:"追加到honorvsxiaomi的开头
  honorvsxiaomi.Insert(0, "PK:");
  Console.WriteLine(honorvsxiaomi);
  //使用Remove()方法从honorvsxiaomi中删除索引21以后的字符串
  honorvsxiaomi.Remove(21, honorvsxiaomi.Length - 21);
  Console.WriteLine(honorvsxiaomi);
  //使用Replace()方法将“PK:”替换成“相爱相杀”
  honorvsxiaomi.Replace("PK", "相爱相杀:");
  Console.WriteLine(honorvsxiaomi);
  Console.ReadLine();
}

程序的运行结果如图所示。

5.3.3  StringBuilder类与String类的区别

String对象是不可改变的,每次使用String类中的方法时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的String对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用StringBuilder类。

例如,当在一个循环中将许多字符串连接在一起时,使用StringBuilder类可以提升性能。

[例5.35]创建一个控制台应用程序,在Mian()方法中编写如下代码,验证字符串操作和可变字符串操作的效率。

static void Main(string[] args)
{
  string str = "";//创建空字符串
  long starTime = DateTime.Now.Millisecond;//定义对字符串执行操作的起始时间
  for (int i = 0; i < 10000; i++)//利用for循环执行10000次操作
  {
    str = str + i;//循环追加字符串
  }
  long endTime = DateTime.Now.Millisecond;//定义对字符串操作后的时间
  long time = endTime - starTime;//计算对字符串执行操作的时间
  Console.WriteLine("String消耗时间:" + time);//将执行的时间输出
  StringBuilder builder = new StringBuilder("");//创建字符串生成器
  starTime = DateTime.Now.Millisecond;//定义操作执行前的时间
  for (int j = 0; j < 10000; j++)//利用for循环进行操作
  {
    builder.Append(j);//循环追加字符
  }
  endTime = System.DateTime.Now.Millisecond;//定义操作后的时间
  time = endTime - starTime;//追加操作执行的时间
  Console.WriteLine("StringBuilder消耗时间:" + time);//将操作时间输出
  Console.ReadLine();
}

运行结果如图所示。

通过这一实例可以看出,二者执行的时间差距很大。如果在程序中频繁地附加字符串,建议使用StringBuilder类。

闯关训练:制作一个程序,要求根据标点符号对字符串进行分行操作。

5.4  小结

本章介绍了用于文本处理的Char、String和StringBuilder类。在介绍这3个类时,结合了大量的实例进行讲解,使读者能够从实例中掌握每种类的用法。在学习本章时,读者要重点掌握String类中处理字符串的一些方法,这些方法在开发程序时会经常用到。StringBuilder类允许使用同一个字符串对象进行字符串的维护操作,这样,可以在操作字符串数据的过程中提高效率,尤其是处理大量文字数据时。

5.5  实践与练习

(1)尝试开发一个程序,要求将字符串中的每个字符颠倒输出。

(2)尝试开发一个程序,要求去掉字符串中的所有空格。

(3)尝试开发一个程序,主要实现从字符串中分离文件路径、文件名及扩展名的功能。