C#字符、字符串与StringBuilder类

本文介绍字符、字符串、逐字字符字符串、String类及StringBuilder类的应用。

字符类型与转义字符

C#中,单个字符使用char类型,在.NET Framework中使用Char结构定义。代码中,字符字面量使用一对英文单引号定义,如'a'、'1'、'=';此外,有一些特殊字符需要使用\符号进行转义,如:

  • \\,\字符。
  • \',单引号。
  • \n,换行符。
  • \0,NUL字符。
  • \a,报警。
  • \b,退格符。
  • \f,换页符。
  • \r,回车符。
  • \t,水平制表符。
  • \v,垂直制表符。
  • \",双引号。

char类型可以和整数相互转换,整数表示字符的Unicode编码,如下面的代码。

C#
using System;

namespace csfx_demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((char)67);  // C
            Console.WriteLine((int)'C');  // 67
        }
    }
}

字符串与String类

C#中的字符串使用string类型定义,在.NET Framework定义为String类,代码中,使用string和String调用操作方法的作用是相同的;字符串字面量使用一对英文双引号定义,其中,特殊字符同样使用\符号进行转义,与char中的转义字符相同。

此外,在双引号前添加@字符,可以定义逐字字符字符串,如下面的代码。

C#
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对象内容使用@符号定义为逐字字符字符串,其中的换行符和\符号都保留了原始状态。

逐字字符字符串中,一个双引号应使用两个双引号格式转义,如下面的代码。

C#
using System;

namespace csfx_demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(@"""Hello,C#.""");  // "Hello,C#."
        }
    }
}

代码中,字符串两端的双引号定义字符串字面量,然后首尾各使用两个双引号转义成一个双引号,定义的字符串为"Hello,C#."。

逐字字符字符串中还需要注意{和}符号,如下面的代码。

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,而{{会转义为一个{符号,}}会转义为一个}符号。

下面介绍一些字符串对象的常用操作。

字符串的比较

比较两个字符串的内容是否相等时可以使用==运算符,此运算符会区分字母的大小写,如下面的代码。

C#
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()方法的应用。

C#
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;这两个方法都可以通过第二个参数指定开始搜索的位置。下面的代码演示了相关应用。

C#
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()方法可以将字符串转换为由字符组成的数组,如下面的代码。

C#
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有,如下面的代码。

C#
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()方法判断字符串是否以指定的内容结束,如下面的代码。

C#
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。

连接

字符串连接时,最简单的方法是使用+运算符,如下面的代码。

C#
using System;

namespace csfx_demo
{
    class Program
    {
        static void Main(string[] args)
        {
            int n = 10;
            Console.WriteLine("共有" + n + "条记录");
        }
    }
}

执行代码会显示“共有10条记录”。

请注意,字符串虽然是引用类型,基本类型是String类,但对于字符串字面量来说,每一次连接、删除、替换等操作都会产生新的字符串对象,所以,如果需要大量修改字符串内容,应使用StringBuilder类,执行起来会更有效率,稍后介绍。

插入

Insert()方法中,参数一指定插入位置的索引,参数二指定插入的内容,方法会返回插入内容后的新字符串,下面的代码演示了相关应用。

C#
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()方法中,参数一指定开始删除的位置索引值,参数二指定删除的字符个数,如果不指定则删除从参数一位置开始的所有字符。下面的代码演示了相关应用。

C#
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类型。下面的代码演示了相关应用。

C#
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()方法可以使用指定的内容将字符串分割为字符串数组,下面的代码演示了使用多个字符进行分割的应用。

C#
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。

分割结果中如果不保留空白字符串,可以参考如下代码。

C#
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。

使用字符串内容分割时与上述代码类似,如下面的代码。

C#
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()静态方法,可以将数组或可枚举对象连接为字符串,如下面的代码。

C#
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()方法的参数一指定连接元素的分隔符,如代码中的分号(;),如果不需要分隔符,设置为空字符串即可。参数二指定需要连接的数组或可枚举对象。方法会返回连接后的字符串。

此外,还可以指定开始组合的元素索引和数量,如下面的代码。

C#
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()方法可以截取字符串的部分内容,其中,参数一指定开始截取的位置索引,参数二指定截取的字符数量,不指定时会截取参数一位置开始的所有内容;请注意,如果指定的截取字符数量大于字符串的字符数量会产生异常。下面的代码演示了相关应用。

C#
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()方法则将字符串中的字母转换为大写形式。下面的代码演示了相关应用。

C#
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类型),不指定时默认使用空格符。下面的代码演示了相关应用。

C#
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()方法的应用相似,参数一指定格式化字符串和占位符,第二个参数开始指定占位符对应的数据。其中,参数一中可以使用的格式化字符包括:

  • c或C,货币类型,使用系统区域设置格式(如人民币显示¥符号)。可以使用数字指定显示的小数位。
  • d或D,显示数字。可以使用数字指定显示的整数位,数据的位数不够时会填充前导0。
  • e或E,科学记数形式。
  • f或F,浮点数。可以使用数字指定小数位,如f2表示两位小数。
  • n或N,显示数字分隔符。
  • p或P,显示百分数。可以使用数字指定小数位。
  • x或X,显示十六进制数。使用X时十六进制数中的A~F显示为大写,使用x时显示为小写。

下面的代码演示了相关应用。

C#
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()方法则删除字符串结束位置的空白字符。下面的代码演示了相关应用。

C#
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类

StringBuilder类定义在System.Text命名空间,需要在代码文件的顶部使用using语句引用。StringBuilder类定义了多个版本的构造函数,常用的有:

  • StringBuilder(n),指定初始缓存为n个字符。
  • StringBuilder(s),指定初始内容为s。
  • StringBuilder(s,n),指定初始内容为s,并指定缓存为n个字符。
  • StringBuilder(n,m),指定初始缓存为n个字符,最大为m个字符。

添加StringBuilder对象的内容时可以使用如下方法:

  • Append()方法,可以添加各种类型的数据,如字符串、数字等。
  • AppendFormat()方法,可以通过string.Format()和Console.WriteLine()方法类似的方式添加内容。
  • AppendLine()方法,在添加内容之后会添加一个换行符。

下面的代码演示了StringBuilder对象添加内容的基本操作方法。

C#
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对象添加内容

StringBuilder对象还有一些常用的操作成员,如:

  • Insert(index, obj)方法,将obj添加到index索引位置。
  • Replace(old, new)方法,将old替换为new的内容。还可以通过参数三和和参数四分别指定开始搜索的位置和搜索的字符数量。
  • Remove(index, length)方法,从index索引位置开始删除length个字符。
  • Clear()方法,清除所有内容。
  • ToString()方法,返回StringBuilder对象中包含内容的字符串形式。
  • Length属性,返回StringBuilder对象中的字符数量。

下面的代码演示了相关操作。

C#
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
        }
    }
}

代码执行结果如下图所示。

操作StringBuilder对象