本文介绍字符、字符串、逐字字符字符串、String类及StringBuilder类的应用。
C#中,单个字符使用char类型,在.NET Framework中使用Char结构定义。代码中,字符字面量使用一对英文单引号定义,如'a'、'1'、'=';此外,有一些特殊字符需要使用\符号进行转义,如:
char类型可以和整数相互转换,整数表示字符的Unicode编码,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { Console.WriteLine((char)67); // C Console.WriteLine((int)'C'); // 67 } } }
C#中的字符串使用string类型定义,在.NET Framework定义为String类,代码中,使用string和String调用操作方法的作用是相同的;字符串字面量使用一对英文双引号定义,其中,特殊字符同样使用\符号进行转义,与char中的转义字符相同。
此外,在双引号前添加@字符,可以定义逐字字符字符串,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "c:\\log1.txt\nc:\\log2.txt"; string s2 = @"c:\log1.txt c:\log2.txt"; Console.WriteLine(s1); Console.WriteLine(); // 显示空行 Console.WriteLine(s2); } } }
代码执行结果如下图所示。
本例,s1对象内容使用了普通的字符串,其中的换行符使用\n转义,路径中的\符号使用\\转义;s2对象内容使用@符号定义为逐字字符字符串,其中的换行符和\符号都保留了原始状态。
逐字字符字符串中,一个双引号应使用两个双引号格式转义,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { Console.WriteLine(@"""Hello,C#."""); // "Hello,C#." } } }
代码中,字符串两端的双引号定义字符串字面量,然后首尾各使用两个双引号转义成一个双引号,定义的字符串为"Hello,C#."。
逐字字符字符串中还需要注意{和}符号,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { Console.WriteLine(@"{0}",10); // 10 Console.WriteLine(@"{0}"); // {0} Console.WriteLine(@"{0}{{}}", 99); // 99{} } } }
第一个输出,{0}定义了数据占位符,结果显示参数二的数值10。第二个输出,{0}没有对应的数据,会原样显示{0}。第三个输出,{0}为数据占位符显示为参数二的99,而{{会转义为一个{符号,}}会转义为一个}符号。
下面介绍一些字符串对象的常用操作。
比较两个字符串的内容是否相等时可以使用==运算符,此运算符会区分字母的大小写,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { Console.WriteLine("abc"=="abc"); // True Console.WriteLine("Abc"=="abc"); // False } } }
String.Compare()静态方法同样可以比较两个字符串,其中,前两个参数指定对比的字符串,参数三指定是否忽略大小写,默认为false。方法返回0时,两个字符串相等;返回值小于0时,参数1按排序位置排在参数2之前;返回值大于0时,参数1按排序位置排在参数2之后。下面的代码演示了Compare()方法的应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abc"; string s2 = "Abc"; Console.WriteLine(string.Compare(s1, s2)); // -1 Console.WriteLine(string.Compare(s1, s2, true)); // 0 } } }
字符串对象的Length属性可以返回字符串中的字符数量。IndexOf()方法返回查询内容第一次出现的索引位置,没有找到返回-1;LastIndexOf()方法返回查询内容最后一次出现的索引位置,没有找到返回-1;这两个方法都可以通过第二个参数指定开始搜索的位置。下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s = "abcdefgabcd"; Console.WriteLine(s.Length); // 11 Console.WriteLine(s.IndexOf("abc")); // 0 Console.WriteLine(s.IndexOf("abc", 5)); // 7 Console.WriteLine(s.LastIndexOf("abc")); // 7 Console.WriteLine(s.LastIndexOf("abc", 5)); // 0 } } }
代码中,第一行会显示s字符串的字符数11。第二行显示abc第一次出现的位置,即第一个字符的索引0。第三行,设置从第六个(索引5)开始查询abc,会显示第二个abc出现的位置,即第八个字符(索引7)。第四行显示abc最后一次出现的位置,即第八字符(索引7)。第五行设置查找截止到第六个字符(索引5),则找到的是abc位置是第一个字符的索引0。
ToCharArray()方法可以将字符串转换为由字符组成的数组,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s = "abcd"; char[] ch = s.ToCharArray(); Console.WriteLine(ch.Length); foreach(char c in ch) { Console.WriteLine(c); } } } }
代码首先会显示ch数组的字符数4,然后分行显示字符a、b、c、d。
Contains()方法判断字符串中是否包含指定的内容,包含时返回true,否则返回false有,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s = "abcdefgabc"; Console.WriteLine(s.Contains("abc")); // True Console.WriteLine(s.Contains("xyz")); // False } } }
StartsWith()方法判断字符串是否以指定的内容开始,EndsWith()方法判断字符串是否以指定的内容结束,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s = "abcdefgabc"; Console.WriteLine(s.StartsWith("abc")); // True Console.WriteLine(s.StartsWith("xyz")); // False Console.WriteLine(s.EndsWith("abc")); // True Console.WriteLine(s.EndsWith("xyz")); // False } } }
如代码所示,开始或结束位置的内容匹配时返回true,否则返回false。
字符串连接时,最简单的方法是使用+运算符,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int n = 10; Console.WriteLine("共有" + n + "条记录"); } } }
执行代码会显示“共有10条记录”。
请注意,字符串虽然是引用类型,基本类型是String类,但对于字符串字面量来说,每一次连接、删除、替换等操作都会产生新的字符串对象,所以,如果需要大量修改字符串内容,应使用StringBuilder类,执行起来会更有效率,稍后介绍。
Insert()方法中,参数一指定插入位置的索引,参数二指定插入的内容,方法会返回插入内容后的新字符串,下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abcdefg"; string s2 = s1.Insert(3, "***"); Console.WriteLine(s2); // abc***defg } } }
Remove()方法中,参数一指定开始删除的位置索引值,参数二指定删除的字符个数,如果不指定则删除从参数一位置开始的所有字符。下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abcdefg"; string s2 = s1.Remove(4); string s3 = s1.Remove(4, 2); Console.WriteLine(s2); // abcd Console.WriteLine(s3); // abcdg } } }
Replace()方法中,参数一指定需要替换的内容,参数二指定替换的新内容;方法会返回替换后的新字符串。此方法有两个重载版本,参数一和参数二可以同时使用string类型或者同时使用char类型。下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abcdefg"; string s2 = s1.Replace("def", "*"); string s3 = s1.Replace('d', '*'); Console.WriteLine(s2); // abc*g Console.WriteLine(s3); // abc*efg } } }
Split()方法可以使用指定的内容将字符串分割为字符串数组,下面的代码演示了使用多个字符进行分割的应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abc,def;ghi"; string[] arr = s1.Split(',', ';'); foreach(string s in arr) { Console.WriteLine(s); } } } }
代码中指定使用逗号(,)或分号(;)分割s1字符串的内容,最后分行显示分割后数组的内容,分别是abc、def、ghi。
分割结果中如果不保留空白字符串,可以参考如下代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abc,def,;ghi;"; string[] arr1 = s1.Split(',', ';'); Console.WriteLine(arr1.Length); // 5 // string[] arr2 = s1.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach(string s in arr2) { Console.WriteLine(s); } } } }
分割的arr1数组中默认包含所有元素,其中会有2个空白字符串,显示数组元素的数量(Length属性)为5。arr2数组不包含空白元素,显示成员为abc、def、ghi。
使用字符串内容分割时与上述代码类似,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abc,def;ghi;"; string[] arr1= s1.Split(new string[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries); foreach(string s in arr1) { Console.WriteLine(s); } } } }
实际工作,如果需要更加复杂的分割模式,可以使用正则表达式,后续文章会有详细介绍。
String类的Join()静态方法,可以将数组或可枚举对象连接为字符串,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string[] arr = new string[] { "abc","def","ghi"}; string s = string.Join(";", arr); Console.WriteLine(s); // abc;def;ghi } } }
Join()方法的参数一指定连接元素的分隔符,如代码中的分号(;),如果不需要分隔符,设置为空字符串即可。参数二指定需要连接的数组或可枚举对象。方法会返回连接后的字符串。
此外,还可以指定开始组合的元素索引和数量,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string[] arr = new string[] { "abc","def","ghi","jkl","mno"}; string s = string.Join(";", arr,1,3); Console.WriteLine(s); // def;ghi;jkl } } }
本例,指定从数组的第2个元素(索引1)开始组合3个元素。
Substring()方法可以截取字符串的部分内容,其中,参数一指定开始截取的位置索引,参数二指定截取的字符数量,不指定时会截取参数一位置开始的所有内容;请注意,如果指定的截取字符数量大于字符串的字符数量会产生异常。下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abcdefg"; Console.WriteLine(s1.Substring(3)); // defg Console.WriteLine(s1.Substring(3,3)); // def } } }
本例,第二个调用中的参数二如果设置为大于4的数值就会产生System.ArgumentOutOfRangeException异常,关于异常的捕捉和处理会在后续文章中介绍。
ToLower()方法可以将字符串中的字母转换为小写形式,ToUpper()方法则将字符串中的字母转换为大写形式。下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "AbcDefG"; Console.WriteLine(s1.ToLower()); // abcdefg Console.WriteLine(s1.ToUpper()); // ABCDEFG } } }
PadLeft() 方法可将字符串转换为指定的宽度(字符数),如果指定的宽度大于原字符串字符数,会在原字符串左侧填充字符,如果指定的宽度小于或等于原字符串字符数则不做修改;PadRight()方法则是在原字符串右侧填充字符;两个方法的第一个参数指定宽度(字符数),第二个参数指定填充字符(char类型),不指定时默认使用空格符。下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = "abc"; Console.WriteLine(s1.PadLeft(8,'*')); // *****abc Console.WriteLine(s1.PadRight(8,'*')); // abc**** } } }
String.Format()方法与Console.WriteLine()方法的应用相似,参数一指定格式化字符串和占位符,第二个参数开始指定占位符对应的数据。其中,参数一中可以使用的格式化字符包括:
下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int x = 123; double y = 0.226; Console.WriteLine(string.Format("{0:c2}", y)); // ¥0.23 Console.WriteLine(string.Format("{0:d6}", x)); // 000123 Console.WriteLine(string.Format("{0:e}", y)); // 1.560000e-001 Console.WriteLine(string.Format("{0:f2}", y)); // 0.23 Console.WriteLine(string.Format("{0:p1}", y)); // 22.6% Console.WriteLine(string.Format("{0:X}", x)); // 7B Console.WriteLine(string.Format("{0:n}", 123456)); // 123,456.00 } } }
Trim()方法可以删除字符串开始和结束位置的空白字符,TrimStart()方法删除字符串开始位置的空白字符,TrimEnd()方法则删除字符串结束位置的空白字符。下面的代码演示了相关应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { string s1 = " abc "; Console.WriteLine(s1.Trim().Length); // 3 Console.WriteLine(s1.TrimStart().Length); // 5 Console.WriteLine(s1.TrimEnd().Length); // 4 } } }
代码中,字符串s1中,abc的前面有一个空格,后面有两个空格。第一个输出,Trim()方法删除开始和结束位置的空白字符,只剩下abc,显示的字符数(Length属性)为3。第二个输出只删除了开始位置的1个空格,剩下abc和两个格式,显示字符数为5。第三个输出删除了结束位置的2个空格,剩下开始的1个空格和abc,显示字符数为4。
StringBuilder类定义在System.Text命名空间,需要在代码文件的顶部使用using语句引用。StringBuilder类定义了多个版本的构造函数,常用的有:
添加StringBuilder对象的内容时可以使用如下方法:
下面的代码演示了StringBuilder对象添加内容的基本操作方法。
using System; using System.Text; namespace csfx_demo { class Program { static void Main(string[] args) { StringBuilder sb = new StringBuilder(256); // sb.Append("abc"); Console.WriteLine(sb.ToString()); // sb.AppendFormat(",{0},{1}", "def", "ghi"); Console.WriteLine(sb.ToString()); // sb.AppendLine(); sb.AppendLine("abc"); // sb.Append("def"); Console.WriteLine(sb.ToString()); } } }
StringBuilder对象还有一些常用的操作成员,如:
下面的代码演示了相关操作。
using System; using System.Text; namespace csfx_demo { class Program { static void Main(string[] args) { StringBuilder sb = new StringBuilder("abcghi",256); // sb.Insert(3, "def"); Console.WriteLine(sb.ToString()); // abcdefghi // sb.Replace("def", "***"); Console.WriteLine(sb.ToString()); // abc***ghi // sb.Remove(3, 2); Console.WriteLine(sb.ToString()); // abc*ghi // sb.Clear(); Console.WriteLine(sb.Length); // 0 } } }