小言_互联网的博客

C#中的字符串, String类和StringBuilder类

178人阅读  评论(0)

C#中的字符串, String类和StringBuilder类

1、简介

字符串对大多数计算机程序而言非常普遍. 像文字处理软件和网页应用程序这些程序类型 都广泛采用了字符串. 这使得处理这类应用程序的程序员在字符串处理的效率问题上需要花费额外的心思. 本章会研究C#处理字符串的方法, 分析如何使用String类, 最后还会介绍如何用StringBuilder类. 当程序需要对String对象进行许多改变时会用到StringBuilder类. 这是因为字符串和String对象都是不可改变的, 而StringBuilder对象则可变的. 会在章节内解释和说明细节。

2、String类的应用

字符串是字符的序列. 它可以包含字母, 数字和其他符号. 在C#中把字符序列用一对闭合的双引号包围起来就可以产生文字串. 下面是一些文字串的实例 :

“铁拳无敌俞大猷”

"故园亲侣如相问, 愧我边尘尚未收. "

“2019-05-08”

“mmcmillan@pulaskitech. edu”

字符串可以由来自Unicode 字符集的任何字符组成. 字符串也可以是没有字符而组成的. 这种特殊的字符串被称为是空字符串. 它的形式是由一对彼此相连的双引号构成的(""). 请千万记住这不是表示空格的字符串. 表示空格的字符串形式是" "。

C#中的字符串具有精神分裂的天性——即字符串既是原生类型(native type)又是一种类的对象. 实际上更准确的说法应该是可以把字符串作为原生数值来使用, 但是事实上每个产生的字符串都 是String 类的一个对象. 稍后会说明原因。

2.1、创建String对象

创建字符串的dao, a写法如下所示 :

string name = “Jennifer Ingram”;

当然, 也可以使用两条语句中先声明变量然后再进行赋值. 字符串声明代码的写法看上去就像一个常规的变量, 但是实际上它是创建了String的一个实例。

C#的字符串还允许在字符串中放置转义字符. C 语言程序员和C++语言程序员都很熟悉此技术, 但是对于那些具有VB 背景的人来说它却可能是一个新内容. 转义字符用来把诸如换行符和制表符这类版式字符放置在字符串内. 转义字符由一个反斜杠(\)开始, 后边跟着单独一个表示版式的字母. 例如, \n 说明换行, 而\t 则表示一个制表符. 在下面这行单独字符串中用到了这两种转义字符 :

string name = “第一行文字\n第二行文字\t增加了缩进的文字”;

2.2、常用的String类方法

虽然对字符串可以执行许多操作, 不过有几种操作是最常用的, 它们分别是 :1. 找到子字符串. 2. 获取字符串的长度. 3. 确定字符在字符串中的位置。

下面这段程序就说明了如何执行这些操作. 这里把String 对象实例化成字符串"Hello, world!". 然后把此字符串分离成两个组成段 :第一个单词和第二个单词. 代码如下所示, 后边跟着的是对用到的String 方法的解释说明。

using System;

class Program {
   
    static void Main()
    {
   
        string string1 = "Hello, world!";
        int len = string1.Length;
        int pos = string1.IndexOf(" ");
        string firstWord, secondWord;
        firstWord = string1.Substring(0, pos);
        secondWord = string1.Substring(pos + 1, (len - 1) - (pos + 1));
        Console.WriteLine("单词1 :" + firstWord);
        Console.WriteLine("单词2 :" + secondWord);
        Console.Read();
    }
}

程序首先做的事就是用Length属性来确定对象string1 的长度. 长度简单说就是字符串中所有字符的总数量. 这里会简要解释一下为什么需要知道字符串的长度。

为了把两词的短语分离出单词, 就需要知道怎么分隔单词. 在一个符合格式的短语中, 空格可以用来分隔单词, 所以就需要找到短语中两个单词之间的空格. 这可以用IndexOf 方法做到. 此方法需要一个字符, 然后返回此字符在字符串中的位置. C#中的字符串中的第一个字符在位置0 上, 第二个字符则是在位置1 上, 其他则以此类推. 如果无法在字符串中找到某个字符, 就返回-1。

IndexOf 方法找到了分隔两个单词的空格的位置, 然后就用下一个方法Substring来真地把第一个单词从字符串中抽出来. Substring方法需要两个参数 :开始位置和要抽出字符的数量. Substring方法会把所要求的字符全部从字符串中抽出, 但是如果试图超过字符串的末尾的话, 就无法得到预期的内容。

程序把第一个单词从位置0 开始由字符串中抽离出来, 而且是抽出了pos个数量的字符. 既然pos包含了空格的位置, 那么这样做好像很多余. 但是, 由于初始字符索引是零, 所以这样做才会是正确的数量。

下一步就是把第二个单词抽离出来. 既然知道了空格的位置, 所以就知道了第二个单词是从pos+1开始的. 较困难的部分就是要确定抽离出来的字符的数量, 因为如果超出了字符串的末尾就 无法得到预期的结果了. 这里可以用一个类别公式来完成计算. 首先, 把1和找到的空格位 置相加, 然后用串长减去这个数值. 这样就可以准确地告诉方法要抽离的字符的数量了。

虽然这段程序很有趣, 但是它不是很实用. 实际需要的程序应该是可以从任意长度的符合格式短语中抽离出单词. 我们可以用几种不同的算法来实现. 这里将用到的算法包含下列这些步骤 :

1、找到字符串中第一个空格的位置。
2、抽取单词。
3、从空格后边开始到字符串的末尾构建一个新的字符串。
4、寻找新字符串中的另外一个空格。
5、如果没有其他空格, 那么抽取的单词就从当前位置到字符串的末尾。
6、否则循环返回第2 步重复操作。
下面就是根据此算法编写的代码(从字符串中抽取的每个单词都存储到名为word的集合里面) :

static void Main()
{
   
    string astring = "中文 不 像 英文一样 需要 加 空格";
    int pos;
    string word;
    ArrayList words = new ArrayList();
    pos = astring.IndexOf(" ");
    while(pos > 0)
    {
   
        word = astring.Substring(0, pos);
        words.Add(word);
        //每次拿到词之后都从原字符串中把找到的词和它后面的空格去掉了
        astring = astring.Substring(pos + 1, astring.Length - (pos + 1));
        pos = astring.IndexOf(" ");
        if (pos == -1) {
   
            word = astring.Substring(0, astring.Length);
            words.Add(word);
        }
        Console.WriteLine($"{word}");
    }
    Console.Read();
}

当然, 如果打算在程序中实际使用这个算法, 那么最好把它做成一个函数并且返回一个集合, 如下所示 :

static void Main()
{
   
    string astring = "中文 不 像 英文一样 需要 加 空格";
    ArrayList words = new ArrayList();
    words = SplitWords(astring);
    foreach (object item in words) {
   
        Console.WriteLine($"{item}");
    }
    Console.Read();
}

static ArrayList SplitWords(string astring)
{
   
    string[] ws = new string[astring.Length - 1];
    ArrayList words = new ArrayList();
    int pos;
    string word;
    pos = astring.IndexOf(" ");
    while (pos > 0) {
   
        word = astring.Substring(0, pos);
        words.Add(word);
        astring = astring.Substring(pos + 1, astring.Length - (pos + 1));
        pos = astring.IndexOf(" ");
        if (pos == -1) {
   
            word = astring.Substring(0, astring.Length);
            words.Add(word);
        }
    }
    return words;
}

实际上String类已经有一个把按照指定字符分割字符串的方法了(Split 方法), 而且还有一个方法可以取走一个数据集合并且把几部分组合成一个字符串(Join方法). 下一小节将看到这些方法.。

3、plit方法和Join 方法

把字符串分解成独立的数据段是一种非常常见的功能. 从网络应用软件到日常办公应用软件 范围内的许多程序都把数据存储在一些字符串格式类型里. 为了简化字符串的分解以及再次合并在一起的过程, String类提供了两种可用的方法 :用于分解字符串的 Split 方法, 以及用来把存储在数组中的数据制作成字符串的Join 方法。

Split 方法取得一条字符串后, 就会按照指定字符分割字符串, 并返回包含分割后字符串的数组. 在前一小节的实例中, SplitWords函数始终采用空格作为分隔符. 而在使用Split 方法时则可以使用参数指定分隔符, 分隔符就是此方法的第一个参数. 该参数必须以 char型数组的形式出 现, 而数组的第一个元素将是用作分隔符的字符。

许多应用程序是通过写出用逗号分隔的数据串的方式来输出数据的. 这被称为是逗号分隔值串, 或简称为CSVs. 某些作者则采用逗号分隔这一术语. 逗号分隔串就如同下列这样的形式 :“Mike, McMillan, 3000W. Scenic, North Little Rock, Ar, 72118”. 此串内的每一字符串数据部分都是用逗号进行分隔的. 这里可以用Split 方法把每个逻辑数据块放入到一个数组中, 如下列所示 :

string data = "Mike,McMillan,3000 W. Scenic,North Little Rock,AR,72118"; 
string[] sdata; 
char[] delimiter = new char[] {
   ','}; 
sdata = data.Split(delimiter); 

使用Split方法得到字符串数组后, 就能以常规数组的方法来访问这些数据了 :

foreach (string word in sdata) 
Console.Write(word + " "); 

Split 方法还可以添加第二个参数, 代表了想要将原字符串分割为几部分. 例如, 如果想要把第一个串元素放置在数组的首位置而把串的其余部分放在第二个元素内, 就需要采用 下列方式调用此方法 :

//参数2表示只分割为两部分
sdata = data.Split(delimiter, 2); 

数组内的元素将是这样的 :

第0 个元素——Mike

第1 个元素——McMillan, 3000W. Scenic, North Little Rock, Ar, 72118

现在来讨论另外一种方法, 即用Join 方法从数组变为字符串. 此方法接受两个参数 :参数1代表目标数组, 参数2代表合并为字符串后, 用来分隔每个元素数据的字符。

还应该注意的是该方法通过String类直接调用, 不需要被String的实例调用。

下面这个实例采用了和前面例子相同的数据 :

static void Main()
{
   
    string data = "Mike,McMillan,3000 W. Scenic,North Little Rock,AR,72118";
    string[] sdata;
    char[] delimiter = new char[] {
    ',' };
    sdata = data.Split(delimiter);
    foreach (object item in sdata) {
   
        Console.WriteLine($"{item}");
    }
    //将分割后的字符串数组再以指定分隔符连接到一起
    Console.WriteLine(string.Join(",", sdata));
    Console.Read();
}

可以利用Split方法从其他数据源中获得数据放入自身程序; Join方法可以把数据以字符串的形式从自身程序发送到其他程序中。

4、字符串比较方法

在C#中有几种比较String对象的方法. 最直接的就是使用等号来比较字符串是否相等. 然而还有一些情况要比较字符串之间的其他关系, 例如, 如果希望知道字符串是大于, 小于, 还是等于另外一个字符串, 需要用到String类中的方法了。

字符串之间的互相比较就如同数的比较一样. 但是, 由于"a"是大于还是小于"H"不是直接观察并看不出来, 所以需要借助数字测量方法. 这种测量就是Unicode表. 每一个字符都有一个Unicode值, 操作系统就是用此数值把字符的二进 制表示转化成为字符的形式. 通过使用ASC 函数可以确定字符的Unicode值. ASC 实际上指的就是数的ASCII 码. ASCII 码是一种先于Unicode的早期数字编码, 而ASC 函数是在Unicode包含ASCII 之前被首先开发出来的。

为了找到字符的ASCII 值, 可以采用强制类型转换把字符简单地转换成为一个整数, 如下所示 :

int charCode; 
charCode = (int)'a'; 

上述代码会把charCode的值设置为97。

然后, 两个字符串的比较实际就是比较它们的数字编码. 字符串"a"和字符串"b"不相等, 就是因为编码 97 不同于编码 98. 事实上compareTo方法可以用来确定两个 String对象之间的精确关系. 这里将会看到采用此方法的简单工作原理。

第一个要检测的比较方法就是Equal方法. 此方法由一个String 对象调用, 并使用另外一个String对象作为参数. 接着就会逐个字符的比较两个String对象. 如果这两个String对象每一个字符都相同(以它们的数字编码为基础), 那么方法就会返回一个True值. 否则, 方法就会返回False值. 此方法的调用如下所示 :

string s1 = "foobar"; 
string s2 = "foobar"; 
if (s1.Equals(s2)) 
    Console.WriteLine("它们相等"); 
else 
    Console.WriteLine("它们不相等"); 

下一个比较字符串的方法就是CompareTo. 此方法也是取一个String作为参数, 但是它不会布尔值. 取而代之的是此方法会返回1, -1 或者0, 具体数值要由传递给的字符串和调用此方法的字符串实例之间的关系来决定 :

string s1 = "foobar"; 
string s2 = "foobar"; 
Console.WriteLine(s1.CompareTo(s2)); // returns 0 
s2 = "foofoo"; 
Console.WriteLine(s1.CompareTo(s2)); // returns -1 
s2 = "fooaar"; 
Console.WriteLine(s1.CompareTo(s2)); // returns 1 

CompareTo方法会将调用它的字符串1与指定字符串2进行比较,并返回一个整数,该整数表示字符串1在排序顺序中位于字符串2之前(-1)、之后(1)还是与其出现在同一位置(0)。

替换CompareTo方法的就是Compare方法. Compare方法通过String类直接调用. 此方法会执行和CompareTo方法相同的比较规则, Compare方法的应用如下所示:

static void Main() 
{
    
    string s1 = "foobar"; 
    string s2 = "foobar"; 
    int compVal = String.Compare(s1, s2); 
    switch (compVal) 
    {
    
        case 0: Console.WriteLine(s1 + " " + s2 + " are equal"); 
            break; 
        case 1: Console.WriteLine(s1 + " is less than " + s2); 
            break; 
        case 2: Console.WriteLine(s1 + " is greater than" + s2); 
            break; 
        default: Console.WriteLine("Can't compare"); 
            break; 
    } 
} 

(关于CompareTo和Compare, 的不同之处, 可以参考这篇博客提到的第一点)
另外两种在处理字符串时会很有用的比较方法是StartsWith和EndsWith. 它们需要一个字符串参数, 并检查调用方法的字符串是否以参数字符串作为开始或结束, 如果是返回true, 否则返回false.

下面两段小程序说明了这些方法的用法. 首先, 这里将先说明EndsWith 方法:

using System; 
using System.Collections; 

class Chapter7 
{
    
    static void Main() 
    {
    
        string[] nouns = new string[] {
   "cat", "dog", "bird","eggs", "bones"}; 
        ArrayList pluralNouns = new ArrayList(); 
        foreach (string noun in nouns) 
            if (noun.EndsWith("s")) 
                pluralNouns.Add(noun); 
        foreach (string noun in pluralNouns) 
            Console.Write(noun + " "); 
    } 
} 

这个程序先创建了一个名词数组, 且其中一些名词还是复数的形式. 接着, 程序循环遍历数组的元素, 并且查看名词是否为复数. 如果是, 就把这些名词添加到一个集合里. 然后, 程序遍历集合并且把每个复数名词显示出来。

接下来这个程序采用了相同的基本思想来确定以前缀"tri"开头的单词:

using System; 
using System.Collections; 

class Chapter7 
{
    
    static void Main() 
    {
    
        string[] words = new string[]{
   "triangle", "diagonal", "trimester","bifocal","triglycerides"}; 
        ArrayList triWords = new ArrayList(); 
        foreach (string word in words) 
            if (word.StartsWith("tri")) 
                triWords.Add(word); 
        foreach (string word in triWords) 
            Console.Write(word + " "); 
    } 
} 

5、处理字符串的方法

字符串处理通常包括对字符串的更改. 我们需要在字符串中插入新的字符, 或从字符串中移除字符, 或是用新字符替换旧字符, 以及向字符串添加空格或者从字符 串中移除空格等等. 在 String类中针对这些操作全部有相应的方法, 因而本小节将对这些方法进行讨论。

这里将先以Insert方法开始. 此方法会把某个字符串插入到另外一个字符串的指定位置。

Insert方法会返回新的字符串. 调用此方法的格式如下所示 :

//Insert方法会把targetString插入到新字符串的position索引位置
String1 = String0.Insert(position, targetString);

下面来看一个实例:

static void Main()
{
   
    string s1 = "来了,?欢迎来到苏州程序大白博客!";
    string s2 = "老弟";
    int pos = s1.IndexOf(",");
    s1 = s1.Insert(pos + 1, s2);
    Console.WriteLine(s1);
    Console.Read();
}

运行结果是 :

来了, 老弟?欢迎来到苏州程序大白博客!

此程序逗号索引+1的位置插入了其他字符串。

Insert方法之后下一个最合理的方法就是Remove 方法了. 这种方法需要两个整数参数: 开始索引和要移除字符的数量. 下面的代码在插入新字符串后, 接着又把它从字符串中移除掉:

static void Main()
{
   
    string s1 = "来了,?欢迎来到苏州程序大白博客!";
    string s2 = "老弟";
    int pos = s1.IndexOf(",");
    s1 = s1.Insert(pos + 1, s2);
    Console.WriteLine(s1);
    s1 = s1.Remove(pos + 1, s2.Length);
    Console.WriteLine(s1);
    Console.Read();
}

为了移除新字符串, Remove 方法采用了与插入新字符串相同的位置, 而且通过获取新字符串的长度来计算要移除的长度. 这样做, 就可以随意更改要插入的新字符串, 而不需要修改代码 :

static void Main()
{
   
    string s1 = "来了,?苏州程序大白博客!";
    string s2 = "老大哥";
    int pos = s1.IndexOf(",");
    s1 = s1.Insert(pos + 1, s2);
    Console.WriteLine(s1);
    s1 = s1.Remove(pos + 1, s2.Length);
    Console.WriteLine(s1);
    Console.Read();
}

程序运行结果 :

接下来介绍的方法是Replace方法. 该方法需要两个参数: 要移除掉的字符串和用来替换掉的字符串. 此方方会返回新的字符串. 下面就是Replace方法的使用过程:

static void Main()
{
   
    string[] words = new string[] {
    "大哥", "二哥", "三哥" };
    for (int i = 0; i <= words.GetUpperBound(0); i++) {
   
        words[i] = words[i].Replace("哥", "弟");
        Console.WriteLine(words[i]);
    }
    Console.Read();
}

程序运行结果 :

由于要操作的字符串是一个数组中的元素, 所以需要通过索引来访问它们, 再对它们调用Replace方法

显示来自程序的数据时, 为了数据排列美观, 可能需要在打印区域内对数据显示的对齐格式进行调整. String类包括两种执行对齐操作的方法: PadLeft方法和PadRight方法. PadLeft方法 会对字符串进行右对齐排列, 而PadRight 方法会对字符串进行左对齐排列. 例如, 若果需要在一个10 个字符宽度区域内右对齐打印单词"Hello", 就需要写成下列形式 :


string s1 = "Hello"; 
Console.WriteLine(s1.PadLeft(10)); 
Console.WriteLine("world"); 

程序运行结果 :

下面是PadRight方法的例子 :

string s1 = "Hello";
string s2 = "world";
string s3 = "Goodbye";
Console.Write(s1.PadRight(10));
Console.WriteLine(s2.PadRight(10));
Console.Write(s3.PadRight(10));
Console.WriteLine(s2.PadRight(10));
Console.Read();

程序运行结果 :

还有一个实例说明了如何排列来自数组的数据使其更容易阅读 :

using System;

class Program {
   
    static void Main()
    {
   
        string[,] names = new string[,]
        {
   
            {
   "1504", "Mary", "Ella", "Steve", "Bob"},
            {
   "1133", "Elizabeth", "Alex", "David", "Joe"},
            {
   "2624", "Joel", "Chris", "Craig", "Bill"}
        };
        Console.WriteLine();
        Console.WriteLine();
        for (int outer = 0; outer <= names.GetUpperBound(0); outer++) {
   
            for (int inner = 0; inner <= names.GetUpperBound(1); inner++)
                Console.Write(names[outer, inner] + " ");
            Console.WriteLine();
        }
        Console.WriteLine();
        Console.WriteLine();
        for (int outer = 0; outer <= names.GetUpperBound(0); outer++) {
   
            for (int inner = 0; inner <= names.GetUpperBound(1); inner++)
                Console.Write(names[outer, inner].PadRight(10) + " ");
            Console.WriteLine();
        }
        Console.Read();
    }
}

程序运行结果 :

第一组显示的数据没有进行对齐调整, 而第二组数据是用PadRight 方法显示的。

String类也包含了一个用于连接多个字符串的Concat方法. 该方法会把作为参数的多个字符串联在一起, 然后返回结果字符串。 下面就是使用此方法的过程:

using System; 

class chapter7 
{
    
    static void Main() 
	{
    
         string s1 = "hello"; 
         string s2 = "world"; 
         string s3 = ""; 
         s3 = String.Concat(s1, " ", s2); 
         Console.WriteLine(s3); 
     } 
} 

程序运行结果 :

利用ToLower 方法和ToUpper方法还可以把字符串从小写转换成大写形式(而且反之亦 然). 下面这段程序代码实例说明了这些方法的工作原理:

static void Main()
{
   
    string s1 = "hello";
    s1 = s1.ToUpper();
    Console.WriteLine(s1);
    string s2 = "WORLD";
    Console.WriteLine(s2.ToLower());
    Console.Read();
}

程序运行结果 :

本文章以Trim方法和TrimEnd 方法的讨论结束. 在处理String 对象时, 这些对象有时会有 额外的空格或者其他格式字符出现在字符串的开始或结尾处. Trim方法和TrimEnd 方法将会把空格或其他字符从字符串的任一端移除掉. 人们既可以对指定的单个字符进行整理, 也可以使用字符数组作为参数. 那么就会在字符串中查找字符数组中的每个元素, 并将它们移除

首先来看一个实例, 此实例对一组字符串值的开始和结尾处的空格进行整理:

static void Main()
{
   
    string[] names = new string[] {
    " 铁拳", " 无敌 ", " 俞 ", "大猷 " };
    Console.WriteLine();
    showNames(names);
    Console.WriteLine();
    trimVals(names);
    Console.WriteLine();
    showNames(names);
    Console.ReadLine();
}

static void showNames(string[] arr)
{
   
    for (int i = 0; i <= arr.GetUpperBound(0); i++)
        Console.Write(arr[i]);
}

static void trimVals(string[] arr)
{
   
    char[] charArr = new char[] {
    ' ' };
    for (int i = 0; i <= arr.GetUpperBound(0); i++) {
   
        arr[i] = arr[i].Trim(charArr[0]);
    }
}

程序运行结果 :

下面另外一个实例把HTML代码页的注释内容去掉了HTML注释标记:

static void Main()
{
   
    string[] htmlComments = new string[]{
   
        "<!-- Start Page-Number Function -->",
        "<!-- Get <user> name and password -->",
        "<!-- End Title page -->",
        "<!-- End script -->"
        };
    Console.WriteLine("处理前");
    for (int i = 0; i <= htmlComments.GetUpperBound(0); i++)
        Console.WriteLine(htmlComments[i]);
    char[] commentChars = new char[] {
    '<', '!', '-', '>' };
    for (int i = 0; i <= htmlComments.GetUpperBound(0); i++) {
   
        //观察结果可以很清晰的看到, Trim方法只去掉最靠外侧的指定字符, 夹在其他字符中间的不会处理
        htmlComments[i] = htmlComments[i].Trim(commentChars);
    }
    Console.WriteLine("处理后");
    for (int i = 0; i <= htmlComments.GetUpperBound(0); i++)
        Console.WriteLine(htmlComments[i]);
    Console.ReadLine();
}

程序运行结果 :

6、StringBuilder类

StringBuilder类可以用来处理内容频繁发生改变的字符串. String类的对象本身是不会发生改变的, 每次对一个字符串对象赋值时, 就会产生一个新的对象来保存数值, 我们只是丢弃了旧的对象, 使用了新的字符串对象的引用。

而StringBuilder对象是可变的. 当对StringBuidler对象进行改变时, 改变的就是原始对象而不是创建了另一个副本进行操作. 本节会讨论如何针对程序中 String对象发生改变的那些情况使用StringBuilder类. 本章及本节的内容会以时间测试作为结束, 用来确定处理Stringbuilder 类确实是比处理String类更加有效。

StringBuilder类位于System. Text命名空间中。

6.1、构造StringBuilder对象

这里可以采用三种方法中的一种来构造StringBuilder对象. 第一种方法使用默认构造函数创建:

StringBuilder stBuff1 = new StringBuilder();

这一行代码创建了对象stBuff1, 此对象可保存16 个字符长度的字符串. 该默认长度可以通过带参数的构造函数改变, 就像下面这样:

StringBuilder stBuff2 = nNew StringBuilder(25); 

这一行代码构建了一个初始可以保存25 个字符的对象。

最后介绍的这个构造函数使用字符串作为参数 :


StringBuilder stBuff3 = nNew StringBuilder("Hello,world"); 

以上代码创建的对象长度为16, 这是因为字符串参数没有超过16 个字符。如果字符串参数长度超过16, 那么容量就会设置为32。每次一旦超过StringBuilder对象的容量, 那么容量就会增加16 个字符。

6.2、获取并且设置关于StringBuilder对象的信息

在StringBuilder类中有几种属性可以用来获取有关 StringBuilder对象的信息. Length属性可以得到当前实例中字符的数量, 而Capacity属性则返回了实例的当前容量. MaxCapacity属性会返回当前对象所允许扩展到的最大容量.

下面的程序段说明了这些属性的用法:

//原文代码不能运行, 已修正
static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("铁拳无敌俞大猷");
    Console.WriteLine("stbuff的长度是: " + stBuff.Length.ToString());
    Console.WriteLine("stbuff的容量是: " + stBuff.Capacity.ToString());
    Console.WriteLine("stbuff的最大容量是: " + stBuff.MaxCapacity.ToString());
    Console.ReadLine();
}

程序运行结果 :

Length属性也可以用来设置StringBuilder对象的当前长度, 就如同下面这样 :

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("铁拳无敌俞大猷");
    stBuff.Length = 4;
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

为了确信保持了适于StringBuilder实例的最小容量, 可以调用EnsureCapacity方法, 并且传递一个整数来说明适于对象的最小容量. 下面是实例 :


//如果stBuff容量小于25, 则设置为25, 否则什么都不做
stBuff.EnsureCapacity(25); 

另外一种可用的属性是Chars属性. 这种属性既会返回在参数中指定位置上的字符, 也会 设置字符作为参数来传递. 下面的代码显示了使用Chars属性的一个简单实例:

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("铁拳无敌俞大猷");
    if (stBuff[0] != '大')
        stBuff[0] = '大';
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

6.3、修改StringBuilder对象

对StringBuilder对象的修改包括在对象末尾处添加新的字符串, 在对象中插入字符串, 替换对象中的特定字符串, 以及从对象中移除掉字符. 本小节将会讨论和这些操作相关的方法。

通过使用Append方法可以在StringBuilder对象的末尾处添加字符. 该方法需要字符串值作为参数, 并且把字符串连到对象当前值的末尾. 下面这个程序说明了Append方法的工作原理:

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("铁拳无敌俞大猷");
    String[] words = new string[] {
   
        "是", "个", "非常", "有",
        "热血", "的", "狠人", "他",
        "永远", "是", "少年"
        };
    for (int i = 0; i <= words.GetUpperBound(0); i++)
        stBuff.Append(words[i]);
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

还可以给StringBuilder对象添加格式字符串. 所谓格式字符串就是有格式说明信息的字符串. 格式信息种类非常多, 本节只示范一种常见的格式. 如下所示 :

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder();
    Console.WriteLine();
    //{0:D4}, 冒号前的0代表此处要使用后面第几个参数代替, 0就是第一个; 
    //D4代表, 4位数字格式不足则补零
    stBuff.AppendFormat("Your order is for {0:D4} widgets.", 234);
    stBuff.AppendFormat("\nWe have {0:D4} widgets left.", 12);
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

接下来是Insert 方法. 这种方法允许在当前StringBuilder对象中插入字符串. 该方法需要三个参数. 第一个参数说明了插入的开始位置. 第二个参数则是要插入的字符串. 第三个参数可选, 是一个整数, 用来说明打算在对象中插入字符串的次数。

下面这段小程序说明了Insert 方法的用法 :

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("铁拳无敌俞大猷");        
    Console.WriteLine(stBuff);
    stBuff.Insert(0, "叼 ");
    stBuff.Insert(stBuff.Length, " 狠");
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

略加修改, 可以看到第三个参数的效果 :

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("铁拳无敌俞大猷");        
    Console.WriteLine(stBuff);
    stBuff.Insert(0, "叼 ", 3);
    stBuff.Insert(stBuff.Length, " 狠", 3);
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

StringBuilder类的Remove 方法可以把字符从StringBuilder对象中移除掉. 该方法需要两个参数 : 开始位置和要移除掉的字符的数量. 下面是此方法的工作原理:

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("铁拳无敌俞大猷");        
    Console.WriteLine(stBuff);
    stBuff.Remove(2, 3);
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

还可以用Replace方法来替换StringBuilder对象的字符. 该方法需要两个参数 : 要 替换的旧字符串和要放在替换位置上的新字符串. 下列代码段就实例说明了如何使用这种方法:

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("铁拳无敌俞大猷");        
    Console.WriteLine(stBuff);
    stBuff.Replace("铁拳无敌", "赤子之心");
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

有时需要把StringBuilder 对象转换成字符串, 通常是为了使用String有而StringBuilder没有的方法. 这可以用ToString方法来实现. 这种方法会返回当前 StringBuilder实例的一个字符串实例. 如下例所示 :

static void Main()
{
   
    StringBuilder stBuff = new StringBuilder("ABCDEFG");        
    Console.WriteLine(stBuff);     
    //转换为字符串
    string st = stBuff.ToString();
    //使用只有String类才有的ToLower方法
    st = st.ToLower();
    //将首字母替换为大写
    st = st.Replace(st.Substring(0, 1), st.Substring(0, 1).ToUpper());
    //使用转换后的字符串替换StringBuilder对象内的全部字符
    stBuff.Replace(stBuff.ToString(), st);
    Console.WriteLine(stBuff);
    Console.ReadLine();
}

程序运行结果 :

7、 String类与StringBuilder的性能比较

本文章会以String类与StringBuilder类的性能比较的讨论作为结束. 大家都知道String 对象是不可变的, 而StringBuilder对象则可以. 人们不是总会使用StringBuilder类, 因为StringBuilder类缺 少几种能够合理有效进行字符串处理的方法. 事实是在需要使用String 方法的时候可以把StringBuilder对象转换成String对象, 稍后再转换回去. 但是需要知道何时要用StringBuilder对象, 以及何时只要继续用String对象。

这里用到的测试非常简单. 程序有两个函数 : 分别使用StringBuilder和String对象来对字符串内容进行1万次, 5万次和25万次的累加, 并对比所用试剂, 代码如下

static void Main()
{
   
    int size = 10000;
    Timing timeSb = new Timing();
    Timing timeStr = new Timing();
    Console.WriteLine();
    for (int i = 0; i < 3; i++) {
   
        timeSb.StartTime();
        BuildSB(size);
        timeSb.StopTime();
        timeStr.StartTime();
        BuildString(size);
        timeStr.StopTime();
        Console.WriteLine($"StringBuilder连续增加{size}次字符串长度耗时{timeSb.Result().TotalMilliseconds}毫秒");
        Console.WriteLine($"String连续增加{size}次字符串长度耗时{timeStr.Result().TotalMilliseconds}毫秒");
        Console.WriteLine();
        size *= 5;
    }
    Console.ReadLine();
}
static void BuildSB(int size)
{
   
    StringBuilder sbObject = new StringBuilder();
    for (int i = 0; i < size; i++)
        sbObject.Append("a");
}
static void BuildString(int size)
{
   
    string stringObject = "";
    for (int i = 0; i < size; i++)
        stringObject += "a";
}

程序运行结果 :

操作次数较少的情况下, String对象和StringBuilder对象之间的性能差异可以忽略不计. 当达操作次数达到5万次时, 已经可以对比出StringBuilder类在效率上的巨大优势。

关注苏州程序大白,持续更新技术分享。谢谢大家支持


转载:https://blog.csdn.net/weixin_46931877/article/details/116779375
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场