C#核心笔记——(六)框架基础

发布于:2025-04-19 ⋅ 阅读:(20) ⋅ 点赞:(0)

我们在编程时所需的许多核心功能并不是由C#语言提供的,而是由.NET Framework中的类型提供的。本节我们将介绍Framework在基础编程任务(例如虚的等值比较、顺序比较以及类型转换)中的作用。我们还会介绍Framework中的基本类型,例如String、DateTime和Enum.

本章中的绝大部分类型位于System命名空间下,但以下几种类型除外:
1.StringBuilder类型定义在System。Text命名空间中。该命名空间中还包含用于进行文本编码的类型。
2.CultureInfo及其相关类型定义在System.Globalization命名空间中。
2.Xmlconvert类型定义在System.Xml命名空间中。

6.1 字符串与文本处理

6.1.1 字符

C#中的一个char代表一个Unicode字符。char是System.Char的别名。在第2章中,我们介绍了如何表示char字面量,例如:

char c = 'a';
char newLine = '\n';

System.Char定义了一系列静态方法对字符处理,例如:ToUpper、ToLower和IsWhiteSpace。这些方法既可以通过System.Char类型进行调用也可以使用其别名char进行调用:

Console.WriteLine(System.Char.ToUpper('c'));
Console.WriteLine(char.IsWhiteSpace('\t'));

ToUpper和ToLower会受到最终用户语言环境的影响,这可能会导致微妙的缺陷。例如,下面的表达式在土耳其语言环境中会得到false值:

Console.WriteLine(char.ToUpper('i') == 'I');

因为在土耳其语中,char.ToUpprt(‘i’)的结果为‘Ī’。为了避免这个问题,System.Char和System.String还提供了和语言环境无关的,有Invariant后缀的ToUpper和ToLower。它们会使用英语语言规则:

Console.WriteLine(char.ToUpperInvariant('i') == 'I');

它是以下写法的简化形式:

Console.WriteLine(char.ToUpper('i',System.Globalization.CultureInfo.InvariantCulture) == 'I');

char类型中有相当一部分的静态方法用于字符分类,如表:

静态方法 包含的字符 包含的Unicode分类
IsLetter A-Z,a-z和其他字母字符 UpperCaseLetter LowerCaseLetter TittleCaseLetter ModifierLetter OtherLetter
IsUpper 大小写字母 UpperCaseLetter
IsLower 小写字母 LowerCaseLetter
IsDigit 0-9和其他字母表中的数字 DecimalDigitNumber
IsLetterOrDigit 字母和数字 IsLetter、IsDigit
IsNumber 所有数字以及Unicode分数和罗马数字符号 DecimalDigitNumber LetterNumber OtherNumber
IsSeparator 空格与所有Unicode分隔符 LIneSeparate ParagraphSeparate
IsWhiteSpace 所有分隔符,以及\n、\r、\t、\f和\v LIneSeparate ParagraphSeparate
IsPunctuation 西方和其他字母表中的标点符号 DashPunchtuation Connector Punctuation InitialQuote PunctuationFinalQuotePPunctuation
IsSymbol 大部分其他的可打印符号 MathSymbol ModifierSymbol OtherSymbol
isControl 值小于0x20的不可打印的控制字符。例如\n、\r、\t、\0和0x7F与0x9A之间的字符 (无)

对于更详细的分类,char提供了一个名为GetUnicodeCategory的静态方法,它返回一个UnicodeCategory枚举值,它的成员即表的6-1最右边一列的值。

我们完全由能力通过显示转换一个整数来制造出一个Unicode集之外的char。因此要检测字符的有效性,可以调用char.GetUnicodeCategory方法:如果返回值为UnicodeCategory.OhterNotAssigned那么这个字符就是无效的。

一个char字符占用16给二进制位,这足以表示基本多文种平面(Basic Multilingual Plane)中的所有Unicode字符。但是如果超出了这个范围,就必须使用替代组(Surrogate pairs)。

6.1.2 字符串

C#中的string(==System.String)是一个不可变的(不可修改)的字符序列。在第二章笔记中,我们介绍了如何表示一个字符串字面量,执行相等比较以及如何连接两个字符串。本章我们将介绍其余字符串处理函数:System.String类的静态和实例成员函数。

6.1.2.1 创建字符串

创建字符串的最简单方法就是将字面量赋给一个变量,这和我们在第2章的做法一样:

string s1 = "Hello";
string s2 = "First Line\r\nSecond Line";
string s3 = @"\\r_server\n_fileshare\t_helloworld.cs";
Console.WriteLine(s1);
Console.WriteLine(s2);
Console.WriteLine(s3);

若要创建一个重复的字符序列,可以使用string类的构造器:

Console.WriteLine(new string('*',10));//**********

我们还可以从char数组来构造一个字符串,而ToCharArray方法则执行了相反的操作:

char[] ca = "Hello".ToCharArray();
string sca = new string(ca);
Console.WriteLine(sca);//Hello

string类的重载构造器可以接收各种(不安全的)指针类型,以便从类似char*这种类型中创建字符串。

6.1.2.2 null和空字符串

空字符串指长度为零的字符串。我们可以使用字面量或静态string.Empty字段来创建一个空字符串。若要判断一个字符串是否为空字符串,则可以执行一个相等比较,或测试它的Length属性:

string empty = "";
Console.WriteLine(empty == "");           //True
Console.WriteLine(empty == string.Empty); //True
Console.WriteLine(empty.Length == 0);     //True

字符串是引用类型,因此它可以为null:

string nullString = null;
Console.WriteLine(nullString == null);//True
Console.WriteLine(nullString == "");  //False
Console.WriteLine(nullString.Length == 0); //NullReferenceException

我们可以使用静态方法string.IsNullOrEmpty来判断一个字符串是否为null或空字符串。

6.1.2.3 访问字符串中的字符

字符串的索引器可以返回一个指定索引位置的字符。和所有操作字符串的方法相似,索引是从0开始计数的。

string str = "abcde";
char letter = str[1];
Console.WriteLine(letter);//letter == 'b'

string还实现了IEnumerable,所以可以用foreach遍历它的字符:

foreach (char c in "abc")
{
   
    Console.Write(c + ",");//1,2,3
}

6.1.2.4 字符串内搜索

在字符串内执行搜索的最简单方法是StartsWith、EndsWith和Contains,这些方法均返回true或false:

Console.WriteLine("quick brown fox".StartsWith("quick"));//True
Console.WriteLine("quick brown fox".EndsWith("fox"));//True
Console.WriteLine("quick brown fox2".EndsWith("fox"));//false
Console.WriteLine("quick brown fox".EndsWith("fox"));//True
Console.WriteLine("quick brown fox".Contains("brown"));//True

StartsWith和EndsWith提供了重载方法,使用StringComparsion枚举或者CultureInfo对象来控制大小写和文化相关的规则。其默认行为是使用当前文化规则执行区分大小写的匹配。以下代码则使用了不变文化规则执行不区分大小写的搜索:

bool isaBc = "abcdef".StartsWith("aBc", StringComparison.InvariantCultureIgnoreCase);
Console.WriteLine(isaBc); //True

Contains则没有提供这种便利的重载方法,但是可以使用IndexOf方法实现相同的效果。

IndexOf的功能更强,它返回指定字符或者字符串的首次出现的位置(-1则表示该子字符串不存在):

Console.WriteLine("abcdef".IndexOf("cd"));

IndexOf也提供了重载方法,不但接受StringComparison枚举值,还可以接受startPosition参数,指定初始搜索位置。

Console.WriteLine("abcde abcde".IndexOf("CD",6,StringComparison.CurrentCultureIgnoreCase));//8

LastIndexOf和IndexOf类似,只是它从后向前进行搜索的。

IndexOfAny返回和字符集中的任意一个字符第一个匹配的位置:

Console.WriteLine("ab,cd ef".IndexOfAny(new char[] {
    ' ',','}));//2
Console.WriteLine("pas5wOrd".IndexOfAny("0123456789".ToCharArray()));//3

LastIndexOfAny则从相反方向执行相同操作。

6.1.2.5 字符串处理

string是不可变的,因此所有“处理”字符串的方法都会返回一个新的字符串,而原始的字符串则不受影响(其效果和重新为一个字符串变量赋值一样)。

Substring方法可以提取部分字符串:

string left3 = "12345".Substring(0,3);
string mid3 = "12345".Substring(1,3);
Console.WriteLine(left3);//123
Console.WriteLine(mid3);//234

若省略长度,则会得到剩余的字符串:

string end3 = "12345".Substring(2);
Console.WriteLine(end3);//345

Insert和Remove在特定的位置插入或者删除一些字符:

string s1 = "helloworld".Insert(5, ",");
Console.WriteLine(s1);       //hello,world
string s2 = s1.Remove(5, 2); 
Console.WriteLine(s2);       //helloorld

PadLeft和PadRight会特定的字符(如果未指定则使用空格)将字符串填充为指定的长度:

Console.WriteLine("12345".PadLeft(9,'*')); //****12345
Console.WriteLine("12345".PadLeft(9));//    12345

如果输入字符串长度大于填充长度,则返回不发生变化的原始字符串。

TrimStart和TrimEnd会从字符串的开始或结尾删除指定的字符,Trim则是从开始和结尾执行删除操作。这些方法默认会删除空白字符(包括空格、制表符、换行和这些字符的Unicode变体):

Console.WriteLine("   abc \t\r\n ".Trim().Length);//3

Replace会替换字符串中所有(非重叠的)特定字符或子字符串:

Console.WriteLine("to be done".Replace(" "," | "));//to | be |done
Console.WriteLine("to be done".Replace(" ", ""));//tobedone

ToUpper和ToLower会返回与输入字符串相对应的大写和小写字符串。默认情况下,它会受用户当前语言设置的影响;ToUpperInvariant和ToLowerInvariant则总是应用英语字母表规则。

6.1.2.6 字符串的分割与连接

Split将字符串分割为若干部分:

string[] words = "The quick brown fox".Split();

foreach (string word in words)
    Console.Write(word + "|"); //The|quick|brown|fox|

默认情况下,Split使用空白字符作为分隔符;重载的方法也可以接收char和string分隔符的params数组。Split还可以接受一个StringSplitOptions枚举值以删除空白项。这在一行文本中有多种单词分隔符时很有用。

静态方法Join则执行和Split相反的操作。它需要一个分隔符和字符串的数组:

string[] words = "The quick brown fox".Split();
string together = string.Join(",", words);
Console.WriteLine(together);//The,quick,brown,fox

静态方法Concat和Join类似,但是它仅仅接受一个字符串的params数组,且不支持分隔符。Concat操作和+操作符效果完全相同(实际上编译器会将+转换为Concat):

string sentence = string.Concat("The", "quick", "brown", "fox");
string sameSentence = "The" + "quick" + "brown" + "fox";
Console.WriteLine(sentence);//Thequickbrownfox
Console.WriteLine(sameSentence);//Thequickbrownfox

6.1.2.7 String.Format与组合格式字符串

静态方法Format提供了创建嵌入变量的字符串的便利方法。嵌入的变量(或值)可以时任何类型,而Format则会直接调用它们的ToString方法。

包含嵌入变量的主字符串称为组合格式字符串。调用String.Format时,需要提供一个组合格式字符串,后面紧跟每一个嵌入的变量,例如:

string composite = "It's {0} degrees in {1} on this{2}morning";
string s = string.Format(composite, 35, "Perth", DateTime.Now.DayOfWeek);
Console.WriteLine(s); //It 's 35 degrees in Perth on thisSaturdaymorning

从C#6开始,可以使用插值字符串字面量来达成同样的效果。只需要在字符串前面加上$符号,并将表达式写在花括号中:

string s = $"It's hot this{
     DateTime.Now.DayOfWeek} morning";
Console.WriteLine(s);

花括号里面的每一个数字称为格式项。这些数字对应参数的位置,后面可以跟随:
1.逗号与应用的最小宽度
2.冒号与格式字符串
3.最小宽度用于对齐各个列。如果其值为负数,则左对齐,否则为右对齐,例如:

string composite = "Name={0,-20} Credit Limit={1,15:C}";
Console.WriteLine(string.Format(composite,"Mary",500));
Console.WriteLine(string.Format(composite, "Elizabeth", 20000));

运行结果:

Name=Mary                 Credit Limit=500.00
Name=Elizabeth            Credit Limit=20,000.00

如果不使用string.Format则上述方法可写为:

string composites = "Name=" + "Mary".PadRight(20) + "Credit Limit"+ 500.ToString("C").PadLeft(15);
Console.WriteLine(composites);

上例的信用额度是通过”C“格式字符串转换为货币值的。

6.1.3 字符串的比较

.NET Framework在两个值的比较上划分了两个不同的概念:相等比较和顺序比较。等值比较验证两个实例是否从语义上是相同的,而顺序比较则验证两个实例(如果有的话)按照升序或者降序排列的话,哪一个应当首先出现。

等值比较并不是顺序比较的一个子集。这两种方法各自有不同的用途。例如,两个不同的值却可以有相同的排序位置。

可以使用==操作符或者string的Equals方法来进行字符串的等值比较。后者可以指定一些选项*例如不区分大小写),因此功能更强。

另一个不同点是,如果将变量转换为object类型,则==就不一定是按字符串处理的了。

对于字符串的顺序比较则可使用实例方法CompareTo或者静态方法Compare或CompareOrdinal:这些方法会返回一个正数、负数或者0.这取决于第一个值是在第二个值之后、之前还是同时出现。

6.1.3.1 序列比较于文化相关的字符串比较

字符串比较有两种基本方法:序列比较(ordinal)和文化相关的比较(culture-sensitive)。序列比较会直接将字符串解析为数字(按照它们的Unicode字符数值);而文化相关的比较则参照特定的字母表来解释字符。有两种特殊的文化:”当前文化“,基于计算机控制面板的设定;”不变文化“,在任何计算机上都是相同的(并且和美国文化密切一致)。

对于相等比较,序列和文化相关的算法都是非常有用的。而排序时,人们则通常选择文化相关的比较:因为当按照字符进行排序时,通常需要一个字母顺序表。序列比较依赖的是Unicode的数字位置,这恰好会使英文字母按照顺序排序,但即使是这样也可能不能满足要求。例如,在区分大小写的情况下,考虑如下字符串”Atom“、”autom"和“Zamia"。使用不变文化则其排列顺序将是:

"autom""Atom""Zamia"

而使用序列比较则为:

"Atom""Zamia""autom"

这是因为不变文化封装了一个字母表,它认为大写字符与其对应的小写字符是相邻的(aAbBcCdD…)。然而序列比较算法将所有大写字母排列在前面,然后才是全部小写字母(A…Z,a…z)这实际上回归到了20世纪60年代发明的ASCII字符集了。

6.1.3.2 字符串的相等比较

结果序列比较有局限性,但是字符串的==运算符总是执行区分大小写的序列比较。不带有参数的string.Equals方法也是用同样的方式。这就是string类型的”默认“相等比较的行为。

字符串的==和Equals方法选择序列算法的原因是因为它既高效有确定。字符串相等比较是基础操作,并远比顺序比较使用频繁。

”严格“的相等概念与==运算符的一般用途是一致的。

下面的方法允许执行文化相关的大小写比较:

public bool Equals(string value, StringComparison comparisonType);
public static bool Equals(string a, string b, StringComparison comparisonType);

我们更推荐静态的版本因为它在两个字符串中的一个或者全部为null的时候仍然有效。
StringComparison是枚举类型,其定义如下:

    //
    // 摘要:
    //     Specifies the culture, case, and sort rules to be used by certain overloads of
    //     the System.String.Compare(System.String,System.String) and System.String.Equals(System.Object)
    //     methods.
    public enum StringComparison
    {
   
        //
        // 摘要:
        //     Compare strings using culture-sensitive sort rules and the current culture.
        CurrentCulture = 0,
        //
        // 摘要:
        //     Compare strings using culture-sensitive sort rules, the current culture, and
        //     ignoring the case of the strings being compared.
        CurrentCultureIgnoreCase = 1,
        //
        // 摘要:
        //     Compare strings using culture-sensitive sort rules and the invariant culture.
        InvariantCulture = 2,
        //
        // 摘要:
        //     Compare strings using culture-sensitive sort rules, the invariant culture, and
        //     ignoring the case of the strings being compared.
        InvariantCultureIgnoreCase = 3,
        //
        // 摘要:
        //     Compare strings using ordinal (binary) sort rules.
        Ordinal = 4,
        //
        // 摘要:
        //     Compare strings using ordinal (binary) sort rules and ignoring the case of the
        //     strings being compared.
        OrdinalIgnoreCase = 5
    }

例如:

Console.WriteLine(string.Equals("foo","FOO", StringComparison.OrdinalIgnoreCase));
Console.WriteLine(" " == "ǖ");
Console.WriteLine(string.Equals(" ", "ǖ", StringComparison.CurrentCulture));

上述中的第三个比较是由计算机当前语言设置决定的。

6.1.3.3 字符串的顺序比较

String的实例方法CompareTo执行文化相关的区分大小写的顺序比较,与==运算符不同,CompareTo不使用序列比较。这是因为对于排序来说,文化相关的算法更为有效。
以下是方法的定义:

public int CompareTo(string strB);

实例方法CompareTo实现了IComparable泛型接口,它也是在整个.NET Framework中使用的标准比较协议。这意味着string的CompareTo定义了字符串在应用程序中,作为集合元素时排序的默认行为。
对于其他类型的比较则可以调用静态方法Compare和CompareOrdinal:

        //
        // 摘要:
        //     Compares substrings of two specified System.String objects, ignoring or honoring
        //     their case, and returns an integer that indicates their relative position in
        //     the sort order.
        //
        // 参数:
        //   strA:
        //     The first string to use in the comparison.
        //
        //   indexA:
        //     The position of the substring within strA.
        //
        //   strB:
        //     The second string to use in the comparison.
        //
        //   indexB:
        //     The position of the substring within strB.
        //
        //   length:
        //     The maximum number of characters in the substrings to compare.
        //
        //   ignoreCase:
        //     true to ignore case during the comparison; otherwise, false.
        //
        // 返回结果:
        //     A 32-bit signed integer that indicates the lexical relationship between the two
        //     comparands.
        //     Value – Condition
        //     Less than zero – The substring in strA precedes the substring in strB in the
        //     sort order.
        //     Zero – The substrings occur in the same position in the sort order, or length
        //     is zero.
        //     Greater than zero – The substring in strA follows the substring in strB in the
        //     sort order.
        //
        // 异常:
        //   T:System.ArgumentOutOfRangeException:
        //     indexA is greater than strA.System.String.Length. -or- indexB is greater than
        //     strB.System.String.Length. -or- indexA, indexB, or length is negative. -or- Either
        //     indexA or indexB is null, and length is greater than zero.
        public static int Compare(String? strA, int indexA, String? strB, int indexB, int length, bool ignoreCase);
        //
        // 摘要:
        //     Compares substrings of two specified System.String objects and returns an integer
        //     that indicates their relative position in the sort order.
        //
        // 参数:
        //   strA:
        //     The first string to use in the comparison.
        //
        //   indexA:
        //     The position of the substring within strA.
        //
        //   strB:
        //     The second string to use in the comparison.
        //
        //   indexB:
        //     The position of the substring within strB.
        //
        //   length:
        //     The maximum number of characters in the substrings to compare.
        //
        // 返回结果:
        //     A 32-bit signed integer indicating the lexical relationship between the two comparands.
        //     Value – Condition
        //     Less than zero – The substring in strA precedes the substring in strB in the
        //     sort order.
        //     Zero – The substrings occur in the same position in the sort order, or length
        //     is zero.
        //     Greater than zero – The substring in strA follows the substring in strB in the
        //     sort order.
        //
        // 异常:
        //   T:System.ArgumentOutOfRangeException:
        //     indexA is greater than strA.System.String.Length. -or- indexB is greater than
        //     strB.System.String.Length. -or- indexA, indexB, or length is negative. -or- Either
        //     indexA or indexB is null, and length is greater than zero.
        public static int Compare(String? strA, int indexA, String? strB, int indexB, int length);
        //
        // 摘要:
        //     Compares two specified System.String objects using the specified comparison options
        //     and culture-specific information to influence the comparison, and returns an
        //     integer that indicates the relationship of the two strings to each other in the
        //     sort order.
        //
        // 参数:
        //   strA:
        //     The first string to compare.
        //
        //   strB:
        //     The second string to compare.
        //
        //   culture:
        //     The culture that supplies culture-specific comparison information. If culture
        //     is null, the current culture is used.
        //
        //   options:
        //     Options to use when performing the comparison (such as ignoring case or symbols).
        //
        // 返回结果:
        //     A 32-bit signed integer that indicates the lexical relationship between strA
        //     and strB, as shown in the following table
        //     Value – Condition
        //     Less than zero –strA precedes strB in the sort order.
        //     Zero –strA occurs in the same position as strB in the sort order.
        //     Greater than zero –strA follows strB in the sort order.
        //
        // 异常:
        //   T:System.ArgumentException:
        //     options is not a System.Globalization.CompareOptions value.
        public static int Compare(String? strA, String? strB, CultureInfo? culture, CompareOptions options);
        //
        // 摘要:
        //     Compares two specified System.String objects, ignoring or honoring their case,
        //     and using culture-specific information to influence the comparison, and returns
        //     an integer that indicates their relative position in the sort order.
        //
        // 参数:
        //   strA:
        //     The first string to compare.
        //
        //   strB:
        //     The second string to compare.
        //
        //   ignoreCase:
        //     true to ignore case during the comparison; otherwise, false.
        //
        //   culture:
        //     An object that supplies culture-specific comparison information. If culture is
        //     null, the current culture is used.
        //
        // 返回结果:
        //     A 32-bit signed integer that indicates the lexical relationship between the two
        //     comparands.
        //     Value – Condition
        //     Less than zero –strA precedes strB in the sort order.
        //     Zero –strA occurs in the same position as strB in the sort order.
        //     Greater than zero –strA follows strB in the sort order.
        public static int Compare(String? strA, String? strB, bool ignoreCase, CultureInfo? culture);
        //
        // 摘要:
        //     Compares two specified System.String objects, ignoring or honoring their case,
        //     and returns an integer that indicates their relative position in the sort order.
        //
        // 参数:
        //   strA:
        //     The first string to compare.
        //
        //   strB:
        //     The second string to compare.
        //
        //   ignoreCase:
        //     true to ignore case during the comparison; otherwise, false.
        //
        // 返回结果:
        //     A 32-bit signed integer that indicates the lexical relationship between the two
        //     comparands.
        //     Value – Condition
        //     Less than zero –strA precedes strB in the sort order.
        //     Zero –strA occurs in the same position as strB in the sort order.
        //     Greater than zero –strA follows strB in the sort order.
        public static int Compare(String? strA, String? strB, bool ignoreCase);
        //
        // 摘要:
        //     Compares two specified System.String objects using the specified rules, and returns
        //     an integer that indicates their relative position in the sort order.
        //
        // 参数:
        //   strA:
        //     The first string to compare.
        //
        //   strB:
        //     The second string to compare.
        //
        //   comparisonType:
        //     One of the enumeration values that specifies the rules to use in the comparison.
        //
        // 返回结果:
        //     A 32-bit signed integer that indicates the lexical relationship between the two
        //     comparands.
        //     Value – Condition
        //     Less than zero –strA precedes strB in the sort order.
        //     Zero –strA is in the same position as strB in the sort order.
        //     Greater than zero –strA follows strB in the sort order.
        //
        // 异常:
        //   T:System.ArgumentException:
        //     comparisonType is not a System.StringComparison value.
        //
        //   T:System.NotSupportedException:
        //     System.StringComparison is not supported.
        public static int Compare(String? strA, String? strB, StringComparison comparisonType);
        //
        // 摘要:
        //     Compares substrings of two specified System.String objects using the specified
        //     rules, and returns an integer that indicates their relative position in the sort
        //     order.
        //
        // 参数:
        //   strA:
        //     The first string to use in the comparison.
        //
        //   indexA:
        //     The position of the substring within strA.
        //
        //   strB:
        //     The second string to use in the comparison.
        //
        //   indexB:
        //     The position of the substring within strB.
        //
        //   length:
        //     The maximum number of characters in the substrings to compare.
        //
        //   comparisonType:
        //     One of the enumeration values that specifies the rules to use in the comparison.
        //
        // 返回结果:
        //     A 32-bit signed integer that indicates the lexical relationship between the two
        //     comparands.
        //     Value – Condition
        //     Less than zero – The substring in strA precedes the substring in strB in the
        //     sort order.
        //     Zero – The substrings occur in the same position in the sort order, or the length
        //     parameter is zero.
        //     Greater than zero – The substring in strA follows the substring in strB in the
        //     sort order.
        //
        // 异常:
        //   T:System.ArgumentOutOfRangeException:
        //     indexA is greater than strA.System.String.Length. -or- indexB is greater than
        //     strB.System.String.Length. -or- indexA, indexB, or length is negative. -or- Either
        //     indexA or indexB is null, and length is greater than zero.
        //
        //   T:System.ArgumentException:
        //     comparisonType is not a System.StringComparison value.
        public static int Compare(String? strA, int indexA, String? strB, int indexB, int length, StringComparison comparisonType);
        //
        // 摘要:
        //     Compares substrings of two specified System.String objects using the specified
        //     comparison options and culture-specific information to influence the comparison,
        //     and returns an integer that indicates the relationship of the two substrings
        //     to each other in the sort order.
        //
        // 参数:
        //   strA:
        //     The first string to use in the comparison.
        //
        //   indexA:
        //     The starting position of the substring within strA.
        //
        //   strB:
        //     The second string to use in the comparison.
        //
        //   indexB:
        //     The starting position of the substring within strB.
        //
        //   length:
        //     The maximum number of characters in the substrings to compare.
        //
        //   culture:
        //     An object that supplies culture-specific comparison information. If culture is
        //     null, the current culture is used.
        //
        //   options:
        //     Options to use when performing the comparison (such as ignoring case or symbols).
        //
        // 返回结果:
        //     An integer that indicates the lexical relationship between the two substrings,
        //     as shown in the following table.
        //     Value – Condition
        //     Less than zero – The substring in strA precedes the substring in strB in the
        //     sort order.
        //     Zero – The substrings occur in the same position in the sort order, or length
        //     is zero.
        //     Greater than zero – The substring in strA follows the substring in strB in the
        //     sort order.
        //
        // 异常:
        //   T:System.ArgumentException:
        //     options is not a System.Globalization.CompareOptions value.
        //
        //   T:System.ArgumentOutOfRangeException:
        //     indexA is greater than strA.Length. -or- indexB is greater than strB.Length.
        //     -or- indexA, indexB, or length is negative. -or- Either strA or strB is null,
        //     and length is greater than zero.
        public static int Compare(String? strA, int indexA, String? strB, int indexB, int length, CultureInfo? culture, CompareOptions options);
        //
        // 摘要:
        //     Compares substrings of two specified System.String objects, ignoring or honoring
        //     their case and using culture-specific information to influence the comparison,
        //     and returns an integer that indicates their relative position in the sort order.
        //
        // 参数:
        //   strA:
        //     The first string to use in the comparison.
        //
        //   indexA:
        //     The position of the substring within strA.
        //
        //   strB:
        //     The second string to use in the comparison.
        //
        //   indexB:
        //     The position of the substring within strB.
        //
        //   length:
        //     The maximum number of characters in the substrings to compare.
        //
        //   ignoreCase:
        //     true to ignore case during the comparison; otherwise, false.
        //
        //   culture:
        //     An object that supplies culture-specific comparison information. If culture is
        //     null, the current culture is used.
        //
        // 返回结果:
        //     An integer that indicates the lexical relationship between the two comparands.
        //     Value – Condition
        //     Less than zero – The substring in strA precedes the substring in strB in the
        //     sort order.
        //     Zero – The substrings occur in the same position in the sort order, or length
        //     is zero.
        //     Greater than zero – The substring in strA follows the substring in strB in the
        //     sort order.
        //
        // 异常:
        //   T:System.ArgumentOutOfRangeException:
        //     indexA is greater than strA.System.String.Length. -or- indexB is greater than
        //     strB.System.String.Length. -or- indexA, indexB, or length is negative. -or- Either
        //     strA or strB is null, and length is greater than zero.
        public static int Compare(String? strA, int indexA, String? strB, int indexB, int length, bool ignoreCase, CultureInfo? culture);
        //
        // 摘要:
        //     Compares two specified System.String objects and returns an integer that indicates
        //     their relative position in the sort order.
        //
        // 参数:
        //   strA:
        //     The first string to compare.
        //
        //   strB:
        //     The second string to compare.
        //
        // 返回结果:
        //     A 32-bit signed integer that indicates the lexical relationship between the two
        //     comparands.
        //     Value – Condition
        //     Less than zero –strA precedes strB in the sort order.
        //     Zero –strA occurs in the same position as strB in the sort order.
        //     Greater than zero –strA follows strB in the sort order.
        public static int Compare(String? strA, String? strB);
        //
        // 摘要:
        //     Compares substrings of two specified System.String objects by evaluating the
        //     numeric values of the corresponding System.Char objects in each substring.
        //
        // 参数:
        //   strA:
        //     The first string to use in the comparison.
        //
        //   indexA:
        //     The starting index of the substring in strA.
        //
        //   strB:
        //     The second string to use in the comparison.
        //
        //   indexB:
        //     The starting index of the substring in strB.
        //
        //   length:
        //     The maximum number of characters in the substrings to compare.
        //
        // 返回结果:
        //     A 32-bit signed integer that indicates the lexical relationship between the two
        //     comparands.
        //     Value – Condition
        //     Less than zero – The substring in strA is less than the substring in strB.
        //     Zero – The substrings are equal, or length is zero.
        //     Greater than zero – The substring in strA is greater than the substring in strB.
        //
        // 异常:
        //   T:System.ArgumentOutOfRangeException:
        //     strA is not null and indexA is greater than strA.System.String.Length. -or- strB
        //     is not null and indexB is greater than strB.System.String.Length. -or- indexA,
        //     indexB, or length is negative.
        public static int CompareOrdinal(String? strA, int indexA, String? strB, int indexB, int length);
        //
        // 摘要:
        //     Compares two specified System.String objects by evaluating the numeric values
        //     of the corresponding System.Char objects in each string.
        //
        // 参数:
        //   strA:
        //     The first string to compare.
        //
        //   strB:
        //     The second string to compare.
        //
        // 返回结果:
        //     An integer that indicates the lexical relationship between the two comparands.
        //     Value – Condition
        //     Less than zero –strA is less than strB.
        //     Zero –strA and strB are equal.
        //     Greater than zero –strA is greater than strB.
        public static int CompareOrdinal(String? strA, String? strB);

后面两个方法,是前面两个方法的快捷调用形式。

所有的顺序比较都放回正数、负数或者零。者取决于第一个值是在第二个值之后,之前还是相同的位置:

Console.WriteLine("Boston".CompareTo("Austin"));//1
Console.WriteLine("Boston".CompareTo("Boston"));//0
Console.WriteLine("Boston".CompareTo("Chicago"));//-1
Console.WriteLine("Boston0".CompareTo("Boston1"));//-1
Console.WriteLine("Boston2".CompareTo("Boston1"));//1
Console.WriteLine("ǖ".CompareTo("ǖ"));//0
Console.WriteLine("foo".CompareTo("FOO"));//-1

以下语句使用当前文化进行不区分大小写的比较:

Console.WriteLine(string.Compare("foo", "FOO", true));//0

6.1.4 StringBuilder

StringBuilder类(System.Text命名空间)表示一个可变(可编辑)的字符串。
StringBuilder可以直接进行子字符串的Append、Insert、Remove和Replace而不需要替换整个StringBuilder。

StringBuilder的构造器可以选择接受一个初始字符串值,及其内部容量的初始值(默认为16个字符)。如果需要更大的容量,则StringBuilder会自动(以较小的性能代价)调整它的内部结构,以至其最大的容量(默认为int.MaxValue)。

StringBulider一般通过反复调用Append来构建较长的字符串,这比反复连接字符串类型对象要高效得多。

StringBuilder sb = new StringBuilder();
for(int i = 0; i < 50; i++)
{
   
    sb.Append(i + ",");
}
Console.WriteLine(sb.ToString());

输出结果:

0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,

在上述例子中,表达式i+","表示我们仍然在反复连接字符串。但是由于我们使用的字符串很小,因此这个操作的性能开销非常少,并不会随着循环迭代而增长。然而,为了实现最好的性能,我们可以将循环体修改为:

StringBuilder sb = new StringBuilder();
for(int i = 0; i < 50; i++)
{
   
    sb.Append(i);
    sb.Append(",");
}
Console.WriteLine(sb.ToString());

AppendLine执行Append操作,随后添加一个换行序列(在Windows下为”\r\n“)。而AppendFormat则接受一个组合格式字符串,这和String.Format是类似的。除了Insert、Remove和Replace方法(Replace方法和字符串的Replace方法类似),StringBuilder还定义了Length属性和一个可写的索引器,以获得/设置每一个字符。

如果要清除StringBuilder的内容,可以创建一个新的StringBuilder或者将其Length设置为零。

将StringBuilder的Length属性设置为0并不会减小其内部容量。因此,如果之前StringBuilder已经包含了一百万个字符,则它在Length设置为0后仍然占用2MB的内存。因此,如果希望释放这些内存,则必须新建一个StringBuilder,然后将旧的对象清除出作用域(从而可以被垃圾回收)。

6.1.5 文本编码和Unicode

字符集是一种字符配置,每一对配置包含了数字码或者代码点(code point)。常用的字符集由两种:Unicode和ASCII。Unicode具有约一百万个字符的地址空间,目前已经分配的大约有100000个。Unicode包括世界上使用最广泛的语言、一些历史语言及特殊符号。ASCII字符集只是Unicode字符集的前128个字符。它包括US风格键盘上的大多数字符。ASCII比Unicode出现早30年,有时仍以其简单性和高效性而得到应用,它的每一个字符是用一个字节表示的。

.NET类型系统的设计使用的是Unicode字符集,但是它隐含支持ASCII字符集,因为ASCII字符集是Unicode的子集。

文本编码(text encoding)是将字符从数字代码点映射到二进制表示的方法。在.NET中,文本编码主要用预处理文本文件和流。当将一个文本文件读取到字符串时,文本编码器(text encoder)会将文件数据从二进制转换为char和string类型使用的内部Unicode表示。文本编码能够限制哪些字符被识别并影响存储效率。

.NET的文本编码分为两类:
一类是将Unicode字符映射到其他字符集
一类是使用标准的Unicode编码模式

第一类包含遗留的编码方式,例如IBM的EBCDIC,以及包含前128个区域扩展字符的8位字符集(这种将字符集字以代码页进行区分的方法,在Unicode之前就已经普遍存在了)。ASCII编码也属于这一类:它将对前128个字符编码,然后去掉其他字符。这个分类也包含GB18030(这种编码方式并非遗留编码方式),这种编码是从2000年以后,在中国开发或者在中国销售的应用程序的强制编码标准。

第二类是UTF-8、UTF-16、UTF-32。每一种编码方式在空间的使用效率都有所差别。UTF-8对于大多数文本而言是最具空间效率的:它使用1~4个字节来表示每一个字符。前128个字符只需要一个字节,这样它就可以兼容ASCII.UTF-8是最普遍的文本文件和流编码方式(特别是在Internet上),并且是.NET中默认的流的I/O编码方式(事实上,它几乎是所有语言隐含的默认编码方式)。

UTF-16使用一个或者两个16位字来表示一个字符,它是.NET内部表示字符和字符串的方式。有一些程序也使用UTF-16来写入文件内容。

UTF-32是空间效率最低的:每一个代码点直接对应一个32位数,所以每一个字符都会占用4个字节。因此,UTF-32很少使用。然而由于每一个字符都有同样的字节数,因此它可以简化随机访问操作。

6.1.5.1 获取一个Encoding对象

System.Text中的Encoding类是封装文本编码的基类型。它有一些子类,封装了具有相同特性的编码方式。实例化一个正确配置的编码类的最简单方法是使用标准的IANA(互联网数字分配机构吗Internet Assigned Numbers Authority)字符集名称调用Encoding.GetEncoding方法。

Encoding utf8 = Encoding.GetEncoding("utf-8");
Encoding chinese = Encoding.GetEncoding("GB18030");

最常用的编码也可以通过调用Encoding类的特定静态属性获得:

编码名称 Encoding类的静态属性
UTF-8 Encoding.UTF8
UTF-16 Encoding.Unicode(注意不是UTF-16)
UTF-32 Encoding.UTF-32
ASCII Encoding.ASCII

静态方法GetEncodings返回所有支持的编码方式清单及其标准的LANA名称:

foreach(EncodingInfo info in Encoding.GetEncodings())
    Console.WriteLine(info.Name);

获取编码方式的另一个方法是直接实例化Encoding类。这样做可以通过构造器参数来设置各种选项,包括:
1.在解码,如果遇到一个无效字节系列,是否抛出异常。默认为false.
2.对UTF-16/UTF-32进行编码/解码时是否使用最高有效字节优先(大字节存储顺序)或最低有效字节优先(小字节存储顺序,little endian)。默认值为小字节存储顺序。这也是Windows操作系统的标准。
3.是否使用字节顺序标记(表示字节顺序的前缀)。

6.1.5.2 文件与流I/O编码

Encoding对象最常见的应用是控制文件或流的文本读写操作,例如,下面的代码将“Testing…"以UTF-16的编码方式写入文件data.txt中:

System.IO.File.WriteAllText("data.txt", "testing", Encoding.Unicode);

如果省略最后一个参数,则WriteAllText会使用最普遍的UTF-8编码方式。

UTF-8是所有文件和流I/O的默认文本编码方式。

6.1.5.3 编码为字节数组

Encoding对象可以将文本转换为字节数组,反之亦然。GetBytes方法用指定的编码方式将string转换为byte[];而GetString则将byte[]转换为string:

System.IO.File.WriteAllText("data.txt", "testing"

网站公告

今日签到

点亮在社区的每一天
去签到