我們在編程時所需的許多核心功能并不是由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"