4 字符串
ASP.NET可以快速地开发动态网页,实现复杂的功能,这得益于.NET Framework包含了一个巨大的基础类库,利用它,开发者可以通过编写少量的代码,快速实现各种应用。
字符串操作是Web应用最重要的操作之一。字符串是页面和用户交互的主要方式,用户在页面上的信息输入,页面对用户呈现的反馈信息,主要是使用字符串来实现的,鉴于此,本章将首先介绍ASP.NET开发中的字符串相关的操作技术。
4.1 字符串String
【本节示例参考:\示例代码\C04\Example_String】
System.String是最常用的字符串操作类,用来表示文本,即一系列的Unicode字符,可以帮助开发者完成绝大部分的字符串操作功能。图4.1给出了String类的常用属性和方法。
图4.1 System.String类
下面将从各个应用的角度对String类进行详细的介绍。
4.1.1 比较字符串
比较字符串是指按照字典排序规则,判定两个字符串的相对大小。在String类中,常用的比较字符串的方法包括Compare、CompareTo、CompareOrdinal及Equals,下面进行详细介绍。
说明
字典规则就是在一本英文字典中,出现在前面的单词小于出现在后面的单词。
1.使用Compare方法比较
Compare方法是String类的静态方法,用于全面比较两个字符串对象,有8种重载方式:
(1)int Compare(string strA, string strB)
(2)int Compare(string strA, string strB, bool ignoreCase)
(3)int Compare(string strA, string strB, StringComparison comparisonType)
(4)int Compare(string strA, string strB, bool ignorCase, CultureInfo culture)
(5)int Compare(string strA, int indexA, string strB, int indexB, int length)
(6)int Compare(string strA, int indexA, string strB, int indexB, int length, bool ignorCase)
(7)int Compare(string strA, int, string strB, int indexA, int length, StringComparison comparisonType)
(8)int Compare(string strA, int, string strB, int indexA, int length, bool ignorCase, CultureInfo culture)
在以上的参数列表中,各参数含义如下:
(1)strA和strB:待比较的两个字符串。
(2)ignorCase:指定是否考虑大小写,当取true时忽略大小写,取false时区分大小写。
(3)comparisonType:指示比较是应使用当前区域性还是固定区域性,是应考虑还是应忽略比较字的大小写,是使用字(区分区域性)排序规则还是序号(不区分区域性)排序规则。其取值为StringComparison枚举,如表4.1所示。
表4.1 StringComparison 枚举值列表
(4)indexA和indexB:在当需要比较两个字符串中的子串时,indexA和indexB为strA和strB中子字符串的起始位置。
(5)length:待比较的字符串的最大长度。
(6)culture:字符串的区域性信息,指示字符串的区域性特定信息,如关联的语言、子语言、国家/地区、日历和区域性约定。
Compare方法的返回值如表4.2所示。
表4.2 Compare方法的返回值
下例使用Compare方法来比较两个字符串,其输出结果如注释语句所示。为了本节介绍示例时的方便,假设两个字符串strA=“Hello”,StrB=“World”,下面给出的各个示例代码中均如此。下面的代码将实现利用Compare方法进行比较。
代码4-1 使用Compare比较两个字符串:Default.aspx.cs
1. //定义两个String对象,并对其赋值,本节下面示例代码中不再重复给出 2. System.String strA="Hello"; 3. System.String strB="World"; 4. 5. //字符串比较 6. bool b1=String.Compare(strA,strB); //-1 7. bool b2=String.Compare(strA,strA); //0 8. bool b3=String.Compare(strB,strA); //1
本例使用了Compare的第(1)个重载方法,对于其余重载方法,读者可以自行试验。鉴于内容雷同,此处不再一一给出详细示例。
说明
String类的另一个比较方法CompareOrdinal同Compare方法非常类似,它比较两个字符串,但不考虑区域性问题,在此不再赘述。
2.CompareTo方法
CompareTo方法将当前字符串对象与另一个字符串对象作比较,其作用与Compare类似,返回值也相同。不过同Compare相比,其区别在于:
(1)CompareTo不是静态方法,可以通过一个String对象调用。
(2)CompareTo没有重载形式,只能按照大小写敏感方式比较两个整串。
CompareTo方法的使用如下例所示。
代码4-2 使用CompareTo比较字符串:Default.aspx.cs
1. //CompareTo 2. System.String strA="Hello"; 3. bool b1=strA.CompareTo(strB); //-1
3.Equals方法
Equals方法用于方便地判断两个字符串是否相同,有4种常用的重载形式:
(1)bool Equals(string)
(2)bool Equals(string, StringComparison comparisonType)
(3)static bool Equals(string, string)
(4)static bool Equals(string, string, StringComparison comparisonType)
如果两个字符串相等,Equals()返回值为true;否则,返回false。Equals方法的使用如下例所示。
代码4-3 使用Equals比较两个字符串:Default.aspx.cs
1. //Equals 2. bool b1=String.Equals(strA,strB); //false 3. bool b2=strA.Equals(strB); //false
4.比较运算符
String支持两个比较运算符“= =”和“!=”,分别用于判断两个字符串是否相等,并区分大小写。相对于上面介绍的方法,这两个运算符使用更加直观和方便。下例中,使用“==”和“!=”对“Hello”和“World”进行比较。
代码4-4 使用==和!=比较两个字符串示例:Default.aspx.cs
1. //使用==和!= 2. bool b1=(strA==strB); //false 3. bool b2=(strA!=strB); //true
4.1.2 判定首尾字符串
当需要判定一个字符串是否以特定的字符开头或者结尾的时候,可以用String类的StartsWith/EndsWith。其中,StartsWith方法可以判断一个字符串对象是否以另一个子字符串开头,如果是,返回true;否则返回false。其定义为:
public bool StartsWith(string value);
其中,参数value即待判定的子字符串,使用非常简单,一个示例如下。
代码4-5 使用StartsWith判断首字符串示例:Default.aspx.cs
1. //StartsWith|EndWith 2. bool b1=strA.StartsWith("He"); //true 3. bool b2=strA.StartsWith("MM"); //false
另外,EndsWith方法可以判断一个字符串是否以另一个子字符串结尾,用法和StartsWith相同,不再赘述。
4.1.3 判断是否包含子串
想要判断一个字符串中是否包含某个子串,可以用Contains方法来实现:
public bool Contains (string value)
参数value为待判定的子串。如果包含,返回true;否则返回false。下面的代码判断“Hello”中是否包含两个子串。
代码4-6 使用Contains判断是否包含子串:Default.aspx.cs
1. bool b1=strA.Contains("ll"); //true 2. bool b1=strA.Contains("MM"); //false
4.1.4 定位字符和子串
定位子串是指在一个字符串中寻找其中包含的子串或者某个字符。在String类中,常用的定位子串和字符的方法包括IndexOf/LastIndexOf及IndexOfAny/LastIndexOfAny,下面进行详细介绍。
1.IndexOf/LastIndexOf
IndexOf方法用于搜索在一个字符串中,某个特定的字符或者子串第一次出现的位置,该方法区分大小写,并从字符串的首字符开始以0计数。如果字符串中不包含这个字符或子串,则返回-1。常用的重载形式如下所示。
(1)定位字符:
int IndexOf(char value)
int IndexOf(char value, int startIndex)
int IndexOf(char value, int startIndex, int count)
(2)定位子串:
int IndexOf(string value)
int IndexOf(string value, int startIndex)
int IndexOf(string value, int startIndex, int count)
在上述重载形式中,其参数含义如下:
○ value:待定位的字符或者子串。
○ startIndex:在总串中开始搜索的位置。
○ count:在总串中从起始位置开始搜索的字符数。
下面的代码在“Hello”中寻找字符‘l’第一次出现的位置。
代码4-7 使用IndexOf寻找字符第一次出现位置:Default.aspx.cs
1. String s=”Hello”; 2. int I=s.IndexOf(‘l’)); //2
与IndexOf类似,LastIndexOf用于搜索在一个字符串中,某个特定的字符或者子串最后一次出现的位置,其方法定义和返回值都与IndexOf相同,不再赘述。
2.IndexOfAny/LastIndexOfAny
IndexOfAny方法功能同IndexOf类似,区别在于,它可以搜索在一个字符串中,出现在一个字符数组中的任意字符第一次出现的位置。同样,该方法区分大小写,并从字符串的首字符开始以0计数。如果字符串中不包含这个字符或子串,则返回-1。常用的IndexOfAny重载形式有3种:
(1)int IndexOfAny(char[]anyOf);
(2)int IndexOfAny(char[]anyOf, int startIndex);
(3)int IndexOfAny(char[]anyOf, int startIndex, int count)。
在上述重载形式中,其参数含义如下:
(1)anyOf:待定位的字符数组,方法将返回这个数组中任意一个字符第一次出现的位置。
(2)startIndex:在原字符串中开始搜索的位置。
(3)count:在原字符串中从起始位置开始搜索的字符数。
下例在“Hello”中寻找字符‘l’第一次和最后一次出现的位置。
代码4-8 使用IndexOfAny寻找子串第一次和最后一次出现位置:Default.aspx.cs
1. String s=“Hello”; 2. char[]anyOf={'H','e','l'}; 3. int i1=s.IndexOfAny(anyOf)); //0 4. int i2=s.LastIndexOfAny(anyOf)); //3
同IndexOfAny类似,LastIndexOfAny用于搜索在一个字符串中,出现在一个字符数组中任意字符最后一次出现的位置。
4.1.5 格式化字符串
Format方法用于创建格式化的字符串及连接多个字符串对象。如果读者熟悉C语言中的sprintf()方法,可以了解两者有类似之处。Format方法也有多个重载形式,最常用的是:
static string Format(string format, params object[] args);
其中,参数format用于指定返回字符串的格式,而args为一系列变量参数。可以通过下面的实例来掌握其使用方法。
代码4-9 使用Format设置字符串格式:Default.aspx.cs
1. //Format 2. String newStr=String.Format("{0},{1}!",strA,strB); //Hello,World!
在format参数中包含一些用大括号扩起来的数字,如{0}、{1},这些数字分别一一对应于args参数数组中的变量。在生成结果字符串时,将使用这些变量代替{i}。需要说明的是,这些变量并不要求必须为String类型。
在特定的应用中,Format方法非常方便。例如,想要输出一定格式的时间字符串,便可以使用Format方法,如下面代码所示:
newStr=String.Format("CurrentTime={0:yyyy-MM-dd}",System.DateTime.Now);//形如:2007-05-19
其中,格式字符串“yyyy-MM-dd”指定返回时间的格式如“2007-05-19”,其定义可参考System.Globalization.DateTimeFormatInfo类。
4.1.6 连接字符串
String类包含了两个连接字符串的静态方法,它们是Concat和Join,下面分别进行介绍。
1.Concat方法
Concat方法用于连接两个或多个字符串。如果读者熟悉C语言中的strcat()方法,可以了解两者有类似之处。Concat方法也有多个重载形式,最常用的是:
static string Concat(params string[]values);
其中,参数values用于指定所要连接的多个字符串,可以通过下面的实例来掌握其使用方法。
代码4-10 使用Concat连接字符串:Default.aspx.cs
1. //Concat 2. newStr=""; 3. newStr=String.Concat(strA,"",strB); 4. Console.WriteLine(newStr); //"Hello World"
2.Join方法
Join方法利用一个字符数组和一个分隔符构造新的字符串。它常常用于把多个字符串连接在一起,并用一个特殊的符号来分隔开。Join的常用形式为:
static string Join(string separator, string[]value);
其中,参数separator为指定的分隔符,而values用于指定所要连接的多个字符串数组,下例用“^^”分隔符把“Hello”和“World”连起来。
代码4-11 使用Join连接字符串:Default.aspx.cs
1. //Join 2. newStr=""; 3. String[]strArr={strA,strB}; 4. newStr=String.Join("^^",strArr); 5. Console.WriteLine(newStr); //"Hello^^World"
3.连接运算符“+”
String支持连接运算符“+”,可以方便地连接多个字符串,如下例把“Hello”和“World”连接起来。
代码4-12 使用“+”连接字符串:Default.aspx.cs
1. //使用+ 2. newStr=""; 3. newStr=strA+strB; //"HelloWorld"
4.1.7 拆分字符串
使用Join方法,可以利用一个分隔符把多个字符串连接起来。反过来,使用Split方法可以把一个整串,按照某个分隔字符或者字符串,拆分成一系列小的字符串。例如,把整串“Hello^^World”按照字符“^”进行拆分,可以得到3个小的字符串:“Hello”、“”(空串)和“World”;根据字符串“^^”,则可以得到两个小的字符串:“Hello”和“World”。
1.根据字符拆分
根据字符拆分的Split重载方法是:
public string[]Split(params char[]separator);
其中,参数separator数组包含分隔符。下例把“Hello^^World”根据“^”进行拆分。
代码4-13 根据字符分裂分隔符字符串:Default.aspx.cs
1. //Split 2. newStr="Hello^^World"; 3. char[]separator={'^'}; 4. String[]splitStrings=new String[100]; 5. splitStrings=newStr.Split(separator); 6. int i=0; 7. while(i<splitStrings.Length) 8. { 9. Console.WriteLine(splitStrings[i]) 10. i++; 11. }
输出结果为:
Hello World
2.根据字符串拆分
根据字符拆分的Split重载方法是:public string[]Split(string[] separator,StringSplitOptions options)。
其中,参数separator数组是分隔字符串数组;参数options取值RemoveEmptyEntries时,将过滤空的数组元素,若取值one则返回。下例把“Hello^^World”根据“^^”进行拆分。
代码4-14 根据字符串分裂分隔符字符串:Default.aspx.cs
1. //split 2. String[]separator=new string[]{strB.Text}; 3. String[]splitStrings=new String[100]; 4. splitStrings=newStr.Split(separator,StringSplitOptions.None); 5. int i=0; 6. while(i<splitStrings.Length) 7. { 8. Page.Response.Write(splitStrings[i]+"<br/>"); 9. i++; 10. }
输出结果为:
Hello World
4.1.8 插入字符串
String类包含了在一个字符串中插入新元素的方法Insert,用于在字符串的任意位置插入任意的字符:
○ public string Insert(int startIndex, string value);
其中,参数startIndex用于指定所要插入的位置,从0开始索引;value指定所要插入的字符串。下例中,在“Hello”的字符“H”后面插入“World”,构造一个串“HWorldello”。
代码4-15 使用Insert插入字符串:Default.aspx.cs
1. //Insert 2. newStr=""; 3. newStr=strA.Insert(1,strB); //"HWorldello"
4.1.9 填充字符串
有时候,可能需要对一个字符串进行填充,例如,想要把“Hello”变为长度为20个字符的串,并使用字符“*”进行填充,即变为“***************Hello”。PadLeft方法可以实现这个功能,用于在一个字符串的左侧进行字符填充,使其达到一定的长度。PadLeft有两种重载形式:
○ public string PadLeft(int totalWidth);
○ public string PadLeft(int totalWidth, char paddingChar);
其中,参数totalWidth指定了填充后的字符长度,而paddingChar指定所要填充的字符,如果默认,则填充空格符号。
下例中,实现了对“Hello”的填充操作,使其长度变为20。
代码4-16 使用PadLeft填充字符串:Default.aspx.cs
1. //PadLeft 2. newStr=""; 3. newStr=strA.PadLeft(20,'*'); //"***************Hello"
与PadLeft类似,PadRight可以实现对一个字符在其右侧的填充功能,对其不作赘述。
4.1.10 删除字符串
String类包含了删除一个字符串的方法,可以用Remove方法在任意位置删除任意长度的字符串,也可以使用Trim/TrimEnd/TrimStart方法剪切掉字符串中的一些特定字符。
1.Remove方法
Remove方法从一个字符串的制定位置开始,删除指定数量的字符。最常用的为:
public string Remove( int startIndex, int count);
其中,参数startIndex用于指定所要开始删除的位置,从0开始索引;count指定所要删除的字符数量。下例中,把“Hello”中的“ell”删掉。
代码4-17 使用Remove删除字符串:Default.aspx.cs
1. //Remove 2. newStr=""; 3. newStr=strA.Remove(1,3); //"Ho"
2.Trim/TrimStart/TrimEnd方法
若想把一个字符串首尾处的一些特殊字符剪切掉,如去掉一个字符串首尾的空格等,可以使用String的Trim方法。其形式为:
○ public string Trim ();
○ public string Trim (params char[]trimChars);
其中,参数trimChars数组包含了指定所要去掉的字符,如果默认,则删除空格符号。下例中,实现了对“@Hello# $”的净化,去掉首尾的特殊符号。
代码4-18 使用Trim去掉首尾的特殊符号:Default.aspx.cs
1. //Trim 2. newStr=""; 3. char[]trimChars={'@','#','$',''}; 4. String strC="@Hello#$"; 5. newStr=strC.Trim(trimChars); //"Hello"
另外,与Trim类似,TrimStart和TrimEnd分别剪切掉一个字符串开头和结尾处的特殊字符。
4.1.11 复制字符串
String类包含了复制字符串方法Copy和CopyTo,可以完成对一个字符串及其一部分的复制操作。
1.Copy方法
若想把一个字符串复制到另一个字符串中,可以使用String的静态方法Copy来实现,其形式为:
static string Copy(string str);
其中,参数str为需要复制的源字符串,返回目标字符串。下例中,把TextBoxA中的字符串复制到newStr中。
代码4-19 使用Copy复制字符串:Default.aspx.cs
1. //Copy 2. newStr=""; 3. newStr=String.Copy(strA); //"Hello"
2.CopyTo方法
CopyTo方法可以实现Copy同样的功能,但功能更为丰富,可以复制源字符串中的一部分到一个字符数组中。另外,CopyTo不是静态方法,其形式为:
public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count);
其中,参数sourceIndex为需要复制的字符起始位置,destination为目标字符数组,destinationIndex制定目标数组中的开始存放位置,而count指定所要复制的字符个数。下例中,把strA字符串“Hello”中的“ell”复制到newCharArr中,并在newCharArr中从第2个元素开始存放。
代码4-20 使用CopyTo复制字符串:Default.aspx.cs
1. //CopyTo 2. char[]newCharArr=new char[100]; 3. strA.CopyTo(2,newCharArr,0,3); //"Hel"
4.1.12 替换字符串
如果想要替换掉一个字符串中的某些特定字符或者某个子串,可以使用Replace方法来实现,其形式为:
○ public string Replace(char oldChar, char newChar);
○ public string Replace(string oldValue, string newValue);
其中,参数oldChar和oldValue为待替换的字符和子串,而newChar和newValue为替换后的新字符和新子串。下例把“Hello”通过替换变为“Hero”。
代码4-21 使用Replace替换字符串:Default.aspx.cs
1. //Replace 2. newStr=strA.Replace("ll","r"); //Hero
4.1.13 更改大小写
String提供了方便转换字符串中所有字符大小写的方法ToUpper和ToLower。这两个方法没有输入参数,使用也非常简单。下例首先把“Hello”转换为“HELLO”,然后再变为小写形式“hello”。
代码4-22 使用ToUpper更改字符串大小写:Default.aspx.cs
1. //ToUpper 2. newStr=strA.ToUpper(); //HELLO 3. //ToLower 4. newStr=strA.ToLower(); //hello
4.2 动态串StringBuilder
【本节示例参考:\示例代码\C04\Example_StringBuilder】
上一节介绍了String类,除此之外,还有一个常用的字符串操作对象StringBuilder,其常用的属性和方法如图4.2所示。
StringBuilder类位于命名空间System.Text中,在使用它时,可以在文件头通过using语句引入该空间:
using System.Text;
声明StringBuilder对象需要使用new关键字,并可以对其进行初始化。如下语句声明了一个StringBuilder对象myStringBuilder,并初始化为“Hello”:
StringBuilder myStringBuilder=new StringBuilder("Hello");
如果不使用using关键字在文件头引入System.Text命名空间,也可以通过空间限定来声明StringBuilder对象:
System.Text.StringBuilder myStringBuilder=new StringBuilder("Hello");
在声明时,也可以不给初始值,然后通过其他方法进行赋值。
图4.2 StringBuilder类
4.2.1 比较String
通过上面的介绍,可以看出StringBuilder与String在许多操作上(如Insert、Remove、Replace)是非常相似的,两者的区别在于:
(1)String为静态串,一旦定义一个String对象,它是不可改变的。在使用其方法(如插入、删除操作)时,都要在内存中创建一个新的String对象,而不是在原对象的基础上进行修改,这就需要开辟新的内存空间。
(2)与String类相比,System.Text.StringBuilder类可以实现动态字符串。此处,动态的含义是指在修改字符串时,系统不需要创建新的对象,不会重复开辟新的内存空间,而是直接在原StringBuilder对象的基础上进行修改。
(3)在操作性能和内存效率方面,StringBuilder要比String好得多,可以避免产生太多的临时字符串对象,特别是对于经常重复进行修改的情况更是如此。而另一方面,String类提供了更多的方法,可以使开发者更快地实现应用。
在两者的选择上,如果应用对系统性能、内存要求比较严格,以及经常处理大规模的字符串,推荐使用StringBuilder对象;否则,可以选择使用String。
4.2.2 设置容量
StringBuilder对象为动态字符串,可以对其设置好的字符数量进行扩充。另外,还可以设置一个最大长度,这个最大长度称为该StringBuilder对象的容量(Capacity)。
为StringBuilder设置容量的意义在于,当修改StringBuilder字符串时,当其实际字符长度(即字符串已有的字符数量)未达到其容量之前,StringBuilder不会重新分配空间;当达到容量时,StringBuilder会在原空间的基础之上,自动分配新的空间,并且容量翻倍。如果不进行设置,StringBuilder默认初始分配16个字符长度。
有两种方式来设置一个StringBuilder对象的容量。
1.使用构造函数
StringBuilder构造函数可以接收容量参数,例如,下面语句声明一个StringBuilder对象sb2,并设置其容量为100。
//使用构造函数设置容量 StringBuilder sb2=new StringBuilder("Hello",100);
2.使用Capacity读/写属性
Capacity属性指定StringBuilder对象的容量,例如下面语句首先声明一个StringBuilder对象sb3,然后利用Capacity属性设置其容量为100。
//使用Capacity属性设置容量 StringBuilder sb3=new StringBuilder("Hello"); sb3.Capacity=100;
4.2.3 追加字符串
追加一个StringBuilder是指将新的字符串添加到当前StringBuilder字符串的结尾处,可以使用Append和AppendFormat来实现这个功能。
1.Append方法
Append方法实现简单的追加功能,其常用形式为:
○ public StringBuilder Append(object value);
其中,参数value既可以是字符串类型,也可以是其他的数据类型,如bool、byte、int等。下例中,把一个StringBuilder字符串“Hello”追加为“Hello World!”。
代码4-23 使用Append追加字符串:Default.aspx.cs
1. //Append 2. StringBuilder sb4=new StringBuilder("Hello"); 3. sb4.Append("World!"); //"Hello World!"
2.AppendFormat方法
AppendFoamat可以实现对追加部分字符串的格式化,可以定义变量的格式,并将格式化后的字符串追加在StringBuilder后面。其常用形式为:
○ StringBuilder AppendFormat(string format, params object[] args);
其中,args数组指定所要追加的多个变量。format参数包含格式规范的字符串,其中包括一系列用大括号括起来的格式字符,如{0:u}。这里,0代表其对应args参数数组中的第0个变量,而“u”定义其格式。下例中,把一个StringBuilder字符串“Today is”追加为“Today is \*当前日期*\”。
代码4-24 使用AppendFormat追加特定格式的字符串:Default.aspx.cs
1. //AppendFormat 2. StringBuilder sb5=new StringBuilder("Today is"); 3. sb5.AppendFormat("{0:yyyy-MM-dd}",System.DateTime.Now);//形如:"Today is 2006-05-20"
4.2.4 插入字符串
StringBuilder的插入操作是指将新的字符串插入到当前StringBuilder字符串的指定位置,如“Hello”变为“Heeeello”,就需要使用插入操作。可以使用StringBuilder类的Insert方法来实现这个功能,其常用形式为:
○ public StringBuilder Insert(int index,object value);
其中,参数index指定所要插入的位置,并从0开始索引,如index=1,则会在原字符串的第2个字符之前进行插入操作;同Append一样,参数value并不仅可取字符串类型。下例中,把一个StringBuilder字符串“Hello”通过插入操作修改为“Heeeello”。
代码4-25 使用Insert插入字符串:Default.aspx.cs
1. //Insert 2. StringBuilder sb6=new StringBuilder("Hello"); 3. sb6.Insert(2,"eee"); //在”He”后面插入,变为"Heeeello!"
4.2.5 删除字符串
StringBuilder的删除操作可以从当前StringBuilder字符串的指定位置,删除一定数量的字符。例如,把“Heeeello”变为“Hello”,就需要使用删除操作。可以使用StringBuilder类的Remove方法来实现这个功能,其常用形式为:
○ public StringBuilder Remove( int startIndex, int length);
其中,参数startIndex指定所要删除的起始位置,其含义同Insert中的index相同;length参数指定所要删除的字符数量。下例中,把一个StringBuilder字符串“Heeeello”通过删除操作修改为“Hello”。
代码4-26 使用Remove删除字符串:Default.aspx.cs
1. //Remove 2. StringBuilder sb7=new StringBuilder("Heeeello"); 3. Sb3.Remove(2,3); //在”He”后面删除3个字符,变为"Hello!"
4.2.6 替换字符串
StringBuilder使用Replace方法来实现替换操作,如想把“Hello”变为“Hero”,就需要使用替换操作,将“ll”替换为“r”。这同String类的Replace方法非常类似,其常用形式包括:
○ public StringBuilder Replace(char oldChar, char newChar);
○ public StringBuilder Replace(string oldValue, string newValue);
其中,参数oldChar和oldValue为待替换的字符和子串,而newChar和newValue为替换后的新的字符和新的子串。下例把“Hello”通过替换变为“Hero”。
代码4-27 使用Replace替换字符串:Default.aspx.cs
1. //Replace 2. StringBuilder sb8=new StringBuilder("Hello"); 3. sb8=sb8.Replace("ll","r"); //Hero
4.3 正则表达式Regex
正则表达式是一个非常大的题目,许多的编程语言和工具都支持正则表达式,.NET类库空间System.Text.RegularExpressions包括了一系列可以充分发挥正则表达式的类,如图4.3所示。
本节,将首先介绍正则表达式的含义,并给出构造正则表达式的技术,然后简单介绍使用Regex类来实现字符串的模式匹配。
图4.3 System.Text.RegularExpression命名空间
4.3.1 正则表达式简介
正则表达式是一种可以用于模式匹配的工具。简单地说,正则表达式就是一套规则,用于去判定其他的元素是否符合它。
例如,在一个用户注册页面中(例如论坛或者交友网站的注册页面),可能有“电子邮件”这一项需要用户填写。Web系统需要判定用户所填写的电子邮件地址是否合法,即是否符合电子邮件地址的规则。众所周知,电子邮件的格式如下:
zhangsan@sina.com
可以抽象为下面的规则:
非空字符序列+’@’+非空字符序列+’.’+com|cn|net
可以称这样的一个规则为正则表达式,它可以作为一个模式,去检验一个字符串是否满足规则。
4.3.2 构造正则表达式
正则表达式的本质是使用一系列特殊字符模式,来表示某一类字符串,如上一节示例中的正则表达式“[a-zA-Z]+@[a-zA-Z]+\.com$”,其中:
(1)“[a-zA-Z]+”指包含1个或多个大小写英文字母的字符串。
(2)“com$”指以“com”结尾的字符串。
(3)“\.”使用转义字符“\”来表示一个普通的字符“.”,因为“.”在正则表达式中也具有特殊的作用;注意在使用转义字符“\”时,需要在字符串前加上“@”符号。
综上所述,“[a-zA-Z]+@[a-zA-Z]+\.com$”可以匹配:非空字符串+“@”+非空字符串+以“.com”结尾的字符串。因此,想要构造正则表达式,必须掌握这些特殊的表达形式,如表4.3所示给出了C#中常用的符号模式。
表4.3 C#正则表达式符号模式
下面给出一些常用的正则表达式,这些都利用了表4.3构造正则表达式的技术。
(1)“^The”:匹配所有以“The”开始的字符串,如“There” 、“Thecat”等。
(2)“he$”:匹配所有以“he”结尾的字符串,如“he”、“she”等。
(3)“ab*”:匹配有一个a后面跟着零个或若干个b的字符串,如“a”、“ab”、“abbb”,……
(4)“ab+”:匹配有一个a后面跟着至少一个或者更多个b的字符串,如“ab”、“abbb”……
(5)“ab?”:匹配有一个a后面跟着零个或者一个b的字符串,包括“a”、“ab”。
(6)“a?b+$”:匹配在字符串的末尾有零个或一个a跟着一个或几个b的字符串。
(7)“ab{2}”:匹配有一个a跟着2个b的字符串,即“abb”。
(8)“ab{2,}”:匹配有一个a跟着至少2个b的字符串,如“abb” 、“abbb”。
(9)“ab{3,5}”:匹配有一个a跟着3~5个b的字符串,如“abbb” 、“abbbb”。
(10)“hi|hello”:匹配包含“hi”或者“hello”的字符串。
(11)“(b|cd)ef”:表示“bef”或“cdef”。
(12)“a.[0-9]”:匹配有一个a后面跟着一个任意字符和一个数字的字符串。
(13)“^.{3}$”:匹配有任意三个字符的字符串。
(14)“[ab]”:表示一个字符串有一个a或b,相当于“a¦b”。
(15)“[a-d]”:表示一个字符串包含小写的a~d中的一个,相当于“a¦b¦c¦d”或者“[abcd]”。
(16)“^[a-zA-Z]”:表示一个以字母开头的字符串。
(17)“[0-9]%”:表示一个百分号前有一位的数字。
(18)“,[a-zA-Z0-9]$”:表示一个字符串以一个逗号后面跟着一个字母或数字结束。
4.3.3 使用Regex类
【本节示例参考:\示例代码\C04\ Example_Match】
Regex类包含若干静态方法,用于使用正则表达式进行字符串匹配,其常用属性和方法如图4.4所示。
图4.4 Regex类图
最常用的方法为Match,它在输入字符串参数中搜索正则表达式的匹配项,并将匹配成功的结果作为单个Match对象返回。其常用形式为:
static Match Match( string input, string pattern);
其中,方法的参数pattern为一个正则表达式,而input为待匹配的字符串。方法返回一个Match对象。Match对象可以表示单个正则表达式匹配的结果,结合下面具体的示例,对其进行简单介绍。
下面是一个使用Regex的Match方法进行正则表达式匹配的示例,用一个正则表达式来验证一个字符串是否是一个合法的电子邮件地址。
代码4-28 利用Regex验证E-mail地址:Default.aspx.cs
1. public void test() 2. { 3. string input="zhangsan@sina.com"; //待匹配的输入串 4. string pattern=@"[a-zA-Z]+@[a-zA-Z]+\.com$"; //正则表达式 5. 6. Regex r=new Regex(pattern); //声明一个Regex对象 7. Match m=r.Match(input); //使用Match方法进行匹配 8. if(m.Success) //循环输出所有的匹配子串 9. { 10. Page.Response.Write(m.Value); 11. } 12. else 13. { 14. Page.Response.Write("Invalid Email Address!"); 15. } 16. }
代码第4行定义了一个正则表达式“[a-zA-Z]+@[a-zA-Z]+\.com$”,其规则为:非空字符串+“@”+非空字符串+“.com”,其具体的含义将在下一节讨论。
第6行声明了一个Regex对象,并通过构造函数为其设置正则表达式;第7行使用Match函数对input字符串进行正则匹配,并将匹配成功的结果串放入一个Match对象。
第8行使用Match对象的Success属性来判断是否匹配成功。如果成功,则输出匹配串,否则,输出错误提示信息。
可以看出,使用Regex类进行字符串的模式匹配非常简单,真正的难点在于正则表达式的构造。
4.4 字符编码
【本节示例参考:\示例代码\C04\Example_Encoding】
ASP.NET中的字符串是Unicode编码类型的,对于汉字和英文的操作是相同的。另外,还可以使用System.Text命名空间中的类来对字符串进行编码和解码。System.Text命名空间中的类如图4.5所示。
图4.5 System.Text命名空间
下面,首先介绍字符串编码的基本知识,然后讨论如何使用System.Text中的各个类实现字符串编码操作。
4.4.1 字符编码概述
计算机是0和1的世界,只能表达数字。那么为了在计算机中表示字符,就必须进行编码,如可以指定用65来代表字符“A”。在计算机发展史上,字符编码的标准经历了多个时代,如图4.6所示。
图4.6 字符编码标准发展轨迹
下面对这几种编码简单介绍如下。
1.ASCII编码
在计算机刚刚诞生时,开发者制定ASCII编码。ASCII码由一个字节中的7位表示,范围是0~127,可以表示128个不同的字符,包括英文字母(如ABC、abc)、数字(如123)、常用符号(如~!@),以及特殊符号(如回车)等。在当时,开发者认为这128个字符就足够满足所有的字符应用了。
2.扩展ASCII编码
但时隔不久,开发者们突然发现,在排版中常用的“制表符”没有出现在这128个字符中,只能对ASCII码进行扩展,使用一个字节的全部8位来表示字符,这称为扩展ASCII码,范围是0~255共256个字符,能表示256个不同的字符。
3.多字节字符集
扩展ASCII码在表达西方语言体系的时候是够用了,但是对于表达东方的方块字时,却出现了问题,这是因为方块字并不是由字母排列组合而成的,仅仅定义一百多个字母就试图表达所有的方块字行不通。
为了解决汉字的编码表示,中国利用连续2个扩展ASCII码的扩展区域(即160以后)来表示一个汉字,该编码标准为GB-2312。后来,日文、韩文、阿拉伯文、台湾繁体(BIG-5)等方块语言地区都使用类似的方法扩展了本地字符集的定义,统一称为多字节字符集(MBCS)。
4.Unicode编码
多字节字符集解决了表达方块字的问题,但这是有缺陷的,因为各个国家地区定义的字符集有冲突。例如,使用GB-2312的软件,在BIG-5的环境下就会显示乱码,反之亦然。为了解决这个冲突,出现了Unicode标准字符集。Unicode使用2个字节表示一个字符,共6万多个字符,包括英文字母和方块字。
4.4.2 字符编码类
ASP.NET中的字符采用Unicode编码标准,但是,有时候也需要同其他编码标准的程序进行字符数据交互,如调用使用ASCII编码、C++实现的COM组件等。为了在各种编码标准的字符间实现转换,.NET提供了几个字符编码类,如表4.4所示。
表4.4 System.Text空间中的编码/解码相关类
由于各个类的使用非常类似,在此只对Encoding类进行介绍,其类属性和方法如图4.7所示。
图4.7 Encoding类
此处的属性介绍如下:
(1)ASCII:获取ASCII(7位)字符集的编码对象。
(2)Unicode:获取Unicode格式的编码对象。
(3)UTF7:获取UTF-7格式的编码对象。
(4)UTF8:获取UTF-8格式的编码对象。
(5)EncodingName:获取编码的可读说明。
常用的方法简介如下:
(1)Covert:将字节数组从一种编码转换为另一种。
(2)GetBytes:将指定的String或字符数组的全部或部分内容编码为字节数组。
(3)GetString:将指定字节数组解码为字符串。
下面通过一个示例来说明其应用,示例将使用Encoding类,显示Unicode字符串“M国”的各种编码形式。
代码4-29 显示编码形式:Default.aspx.cs
1. public void test() 2. { 3. String str="M国"; //C#默认Unicode编码格式 4. 5. //Unicode编码 6. Encoding uni_str=Encoding.Unicode; 7. //获取Unicode编码 8. byte[]uni_byte=uni_str.GetBytes(str); 9. Page.Response.Write("Unicode:"); 10. for(int i=0;i<uni_byte.Length;i++) 11. { 12. Page.Response.Write(uni_byte[i]+"-"); 13. } 14. //获取Unicode编码格式字符串 15. Page.Response.Write(">"+uni_str.GetString(uni_byte)+"<br/>"); //输出:"M国" 16. 17. //ASCII编码 18. Encoding ascii_str=Encoding.ASCII; 19. //获取ASCII编码 20. byte[]ascii_byte=ascii_str.GetBytes(str); 21. Page.Response.Write("ASCII:"); 22. for(int i=0;i<ascii_byte.Length;i++) 23. { 24. Page.Response.Write(ascii_byte[i]+"-"); 25. } 26. //获取ASCII编码格式字符串 27. Page.Response.Write(">"+ascii_str.GetString(ascii_byte)+"<br/>");//输出:"M?" 28. }
第3行,示例首先定义了一个Unicode字符串“M国”,注意.NET默认的编码标准为Unicode。
首先,示例显示“M国”的Unicode编码。第6行声明了一个Unicode编码对象,然后在第8行使用了GetBytes方法得到“M国”的Unicode编码。第10~13输出这个编码,应该如下所示:
Unicode:77-0-253-86
其中,77-0为字符“M”的Unicode编码,而253-86为字符“国”的Unicode编码。可以看出,Unicode使用两个字节表示一个中文或英文字符。
第15行使用GetString方法显示Unicode编码的字符串,输出为“M国”。
然后,示例显示“M国”的Unicode编码。第18行声明了一个ASCII编码对象,然后在第20行使用了GetBytes方法得到“M国”的ASCII编码。第22~25行输出这个编码,如下所示:
ASCII:77-63
其中,77为字符“M”的ASCII编码,而“63”为字符“国”的ASCII编码。
第27行使用GetString方法显示ASCII编码的字符串,输出为“M?”。很明显,可以看出,ASCII试图使用一个字节表示一个字符。对于英文字符而言,没有任何影响。但是对于中文字符,就会丢失一定的信息,无法正常显示。示例运行结果如图4.8所示。
图4.8 字符串编码示例运行结果
承上启下
■ 学完本章后,读者需要回答:
1.能否使用String对象实现字符串的以下操作。
(1)比较:Compare
(2)判定首位:StartsWith|EndsWith
(3)判定子串:Contains
(4)定位子串:IndexOf|IndexOfAny|LastIndexOf|LastIndexOfAny
(5)格式化:Format
(6)连接:Concat|Join
(7)分裂:Split
(8)插入:Insert
(9)填充:PadLeft|PadRight
(10)删除:Remove|Trim/TrimStart/TrimEnd
(11)复制:Copy|CopyTo
(12)替换:Replace
(13)大小写转换:ToUpper|ToLower
2.为什么称StringBuilder对象为动态字符串?它和String对象有何不同之处?
3.如何使用StringBuilder对象完成字符串的以下操作。
(1)设置字符串最大长度:Capacity
(2)追加字符串:Append|AppendFormat
(3)插入字符串:Insert
(4)删除字符串:Remove
(5)替换字符串:Replace
4.什么是正则表达式?是否能够构造匹配URL字符串的正则表达式?
5.如何使用Regex类操作正则表达式?
6.历史上曾经有哪些字符编码标准?.NET中如何实现编码的转换?
■ 在下一章中,读者将会了解:
1.数组的概念。
2.使用数组完成以下操作。
(1)元素访问:GetValue
(2)转化类型:ConvertAll
(3)遍历数组:foreach
(4)排序数组:Sort
(5)查找元素:BinarySearch/Contains
(6)反转数组:Reverse
(7)复制数组:Copy/CopyTo
3.C#中的集合命名空间包含的常用类,如ArrayList、Queue、Stack等。
4.使用ArrayList类完成以下操作。
(1)添加元素:Add/AddRange
(2)插入元素:Insert/InsertRange
(3)删除元素:Remove/RemoveAt/RemoveRange
(4)排序元素:Sort
(5)查找元素:BinarySeach
5.利用Queue类和Stack类来实现队列及堆栈的以下操作。
(1)入队:Enqueue
(2)出队:Dequeue
(3)入栈:Push
(4)出栈:Pop