C#中的char、string和StringBuilder的使用


char 字符

char代表一個Unicode字符,它是System.Char的別名

char someChar = 'a';//定義了一個字符
char newLine= '\n';//這是一個換行符

 System.Char定義了一組靜態方法:

  • ToUpper 將指定的字符轉換為等效的大寫形式
  • ToLower 將指定的字符轉換為等效的小寫形式
  • IsWhiteSpace 判斷指定的字符是否為空白字符
  • ……

例子:

Console.WriteLine(char.ToUpper('c'));//輸出的是一個大寫的C
Console.WriteLine(char.ToLower('c'));//輸出的是還是它自己
Console.WriteLine(char.ToUpper('C'));//輸出的是還是它自己
Console.WriteLine(char.ToLower('C'));//輸出的是一個小寫的c
Console.WriteLine(char.IsWhiteSpace('c'));//輸出為False
Console.WriteLine(char.IsWhiteSpace('\t'));//輸出為True
Console.WriteLine(char.IsWhiteSpace(' '));//輸出為True

可以通過char或者System.Char來調用

例子:

Console.WriteLine(char.ToUpper('c'));//輸出的是一個大寫的C
Console.WriteLine(System.Char.ToUpper('c'));//輸出的是一個大寫的C

現在這邊會有一個問題,可能會引起一個bug,就是ToUpper,ToLower會遵循用戶的地區設置,例如,char.ToUpper('i') == 'I',這句話在土耳其地區設置里就會返回False。

解決辦法就是使用culture-invariant版本的方法,總會應用英語的Culture

  • ToUpperInvariant
  • ToLowerInvariant

例子:

//使用固定區域性的大小寫規則,不依賴於區域性的設置,以下這兩種方式是等價的
Console.WriteLine(char.ToUpperInvariant('i'));//輸出的是大寫的I
Console.WriteLine(char.ToUpper('i', CultureInfo.InvariantCulture));

 char是16bit的,足夠代表基本多語言平面的任何Unicode字符,如果超出這個范圍,那么必須使用surrogate pairs。

 

string 字符串

  • string是System.String的別名
  • string是不可變的
  • string是字符的序列

如何構建string

例子:

string s1 = "Hello";
string s2 = "First Line\r\nSecond Line";
string s3 = @"\\server\fileshare\helloworld.cs";
  • 創建重復字符的字符串

使用string的構造函數創建一個重復指定次數的字符的字符串。

例子:

Console.WriteLine(new string('*', 10));//輸出的結果就是**********
  • 可以從char數組構建字符串

例子:

char[] ca = "Hello".ToCharArray();
string s = new string(ca);

ToCharArray的作用正好相反,把字符串轉成字符數組。

  • string的構造函數也被重載用來接收各種(不安全的)指針類型,目的是從像char*這樣的類型創建字符串。

Null 和 空string

  • 空string的長度是0,通過literal或string.Empty靜態字段來創建

相等性比較的例子:

string empty = "";
Console.WriteLine(empty == ""); // True
Console.WriteLine(empty == string.Empty); // True
Console.WriteLine(empty.Length == 0); // True
  • string可以為null,因為是引用類型
string nullString = null;
Console.WriteLine(nullString == null); // True
Console.WriteLine(nullString == ""); // False
Console.WriteLine(nullString.Length == 0); // NullReferenceException

靜態的string.IsNullOrEmpty通常用來判斷字符串是否為空或者null,我習慣性使用IsNullOrWhiteSpace,這個判斷字符串是否為空或者null或者空白的字符。

 

訪問string里的字符

  • 通過索引器
string str = "abcd";
char letter = str[1]; // letter = 'b'
  • string實現了IEnumerable<char>接口,所以可以foreach里面的每個元素
// 分別依次輸出字符1 、2 、3
foreach (var item in "123")
{
    Console.WriteLine(item);
}

 

在string里進行搜索

最簡單的方法包括:StartsWith,EndsWith和Contains。返回的是true或者false。

Console.WriteLine("HelloWorld.cs".EndsWith(".cs")); // 返回結果為True
Console.WriteLine("HelloWorld.cs".Contains("World")); // 返回結果為True
Console.WriteLine("HelloWorld.cs".EndsWith(".CS")); // 返回結果為False
Console.WriteLine("HelloWorld.cs".Contains("world")); // 返回結果為False

StartsWith,EndsWith的重載方法允許你指定一個StringComparison枚舉或一個CultureInfo對象,以便控制大小寫和區域文化的敏感性,默認使用當前本地化的區域設置(locale),並且區分大小寫。

Console.WriteLine("HelloWorld.cs".StartsWith("hello", StringComparison.InvariantCultureIgnoreCase)); // 返回結果為True

Contains沒有提供類似的重載方法,但是你可以使用IndexOf方法,它會返回給定字符/子字符串在被搜索字符串里的首個位置。

同時,IndexOf提供了重載方法,它可以接收一個起始位置參數(開始搜索的索引值),以及一個StringComparison枚舉

Console.WriteLine("abcde".IndexOf("cd")); // 結果為2
Console.WriteLine("abcde abcde".IndexOf("CD", 6, StringComparison.CurrentCultureIgnoreCase)); // 結果為8

LastIndexOf,它和IndexOf類似,但是它是反向搜索

IndexOfAny,它會返回一組字符里任意一個元素的第一個匹配的位置。

Console.WriteLine("abc,de f".IndexOfAny(new char[] { ' ', ',' })); // 結果為3
Console.WriteLine("sdgp5jesu5fa9afe0".IndexOfAny("0123456789".ToCharArray())); // 結果為4

LastIndexOfAny,功能類似,方向相反

 

操縱或者控制 string

因為string是不可變的,所以所有操縱string的方法返回的都是一個新的string,原來的string是原封不動的。

Substring,會抽取字符串的一部分出來。

string left3 = "12345".Substring(0, 3); // 結果就是123
string mid3 = "12345".Substring(1, 3); // 結果為234
//如果忽略長度,那么就從起始位置一直到字符串的最后
string end3 = "12345".Substring(2); // 結果為345

Insert、Remove,在指定的位置插入、移除字符串。

string s1 = "helloworld".Insert(5, ","); // 結果為hello,world
string s2 = s1.Remove(5, 1); // 結果為helloworld

PadLeft、PadRight,會使用指定的字符(沒有指定就是空格)填充string,以達到指定的長度(如果string原本長度就長於指定的長度,那么它就不變)。

Console.WriteLine("12345".PadLeft(10, '*')); // 輸出結果就是*****12345
Console.WriteLine("12345".PadLeft(10)); // 輸出結果就是     12345

TrimStart,TrimEnd從開始或結尾移除指定的字符(默認是空白符:空格,tab,換行以及Unicode里相應的變種)。

Trim,會把開始和結尾的空白字符都移除。

Console.WriteLine("   abc  \r\n  ".Trim().Length); // 結果為3

Replace,替換所有指定的字符/字符串,(非重疊的)。

Console.WriteLine("hello world".Replace(" ", " | ")); // 結果為hello | world
Console.WriteLine("hello world".Replace(" ", "")); // 結果為helloworld

ToUpper,ToLower,返回string的大/小寫等等效形式。默認情況下也遵循用戶當前的語言設定,與上面的char的方法一樣,不再贅述。

 

拆分、合並字符串

Split方法可以拆分字符串。

  • 默認使用空格作為分隔符
  • 重載方法可以接收param字符數組,或string作為分隔符
  • 可選接收StringSplitOptions枚舉作為參數,有個選項可以移除空的字符串
string[] words = "my name is bob".Split();
//打印結果依次輸出my name is bob四個單詞
foreach (var item in words)
{
    Console.WriteLine(item);
}
string[] split1 = "123-abc".Split('-');
//打印結果依次輸出123和abc兩個字符串
foreach (var item in split1)
{
    Console.WriteLine(item);
}
string[] split2 = "123-abc-".Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
//打印結果依次輸出123和abc兩個字符串,最后一個空項會被移除
foreach (var item in split2)
{
    Console.WriteLine(item);
}

Join(靜態)方法,功能與Split相反,用於合並成一個字符串,它需要一個分隔符和字符串數組。

string[] words = "my name is bob".Split();
Console.WriteLine(string.Join(",", words)); // 輸出結果為一個字符串my,name,is,bob

Concat(靜態)方法,和Join類似,但是只接收params string數組作為參數,無需分隔符。和+的效果一樣,起始編譯器就是把它翻譯成+。

string str1 = string.Concat("hello", "world"); // 結果為helloworld
string str2 = "hello" + "world"; // 結果為helloworld

 

String.Format 和 復合格式的string

Format(靜態)方法,提供了一個方便的方式來構建嵌入變量的字符串,嵌入的變量/值可以是任何類型,Format會調用它們的ToString方法。

含有嵌入變量的string就叫做復合格式string(composite format string)。

當你調用String.Format的時候,你就得傳入一個復合格式string,后邊跟着它里面嵌入的這些變量。

string composite = "ab{0}cd{1}e";
Console.WriteLine(string.Format(composite, "123", 456)); // 結果為ab123cd456e

大括號里的每個數字都叫做格式化項(format item),數值對應參數(argument)的位置,並且后邊可以跟着:

  • 一個逗號,和一個要應用的最小寬度(通常用來對齊列,負數表示左對齊,正數表示右對齊)
  • 一個冒號,和一個格式化字符串(format string)
string composite = "Name={0, -20} Credit Limit={1,15:C}";
Console.WriteLine(string.Format(composite, "Bob", 500));
Console.WriteLine(string.Format(composite, "Elizatech", 20000));

結果如下:

 

 從C#6開始,你可以使用字符串插值的方式(interpolated string literals)。

int value = 32;
Console.WriteLine($"abc{value}"); //結果為abc32

 

比較 string

在.NET里,用來比較兩個string的概念有兩個:

  • 相等性比較,Equality
  • 順序比較,Order

相等性比較就是測試兩個字符串實例在語義上是否相等。而順序比較是指在正序倒序排列的時候,誰應該出現在前面。

相等性比較不是順序比較的子集。

對於字符串相等性的比較來說,可以使用:

  • == 運算符
  • string的某個Equals方法(這種方式有很多選項)

上述兩種方式還有一個重要的差別就是,如果string變量轉換成了object對象,那么==運算符就不再可靠了。

對於字符串的順序比較來說,可以使用:

  • 實例的CompareTo方法
  • 靜態的Compare和CompareOrdinal方法。第一個值在第二個值的后邊,返回正數,第一個值在第二個值的前邊,返回負數,兩個值並列,返回0。

序數 VS 文化 比較(Ordinal VS Culture Comparison)

有兩個基本的算法用來做string比較:

  • Ordinal
  • Culture-sensitive

Ordinal比較,會把字符解析成數字(根據它們的Unicode數值),例如:A 是 U+0041,a 是 U+0061。

Culture-sensitive比較,通過引用特定的字母表來解析字符。

兩個常用或者特殊的Culture:

  • 當前的Culture
  • Invariant Culture

對於相等性比較而言,Ordinal和Culture-specific算法都有用。而對於順序比較來說,更傾向於culture-specific比較(文化相關的),按字母表對string進行排序,所以肯定需要一個字母表。

Ordinal依賴於Unicode的Code point數值,英文字母正好是字母表的順序,不知道是這么設計的還是巧合。

例子:

如果考慮大小寫,對一下三個字符串排序:

"Ada", "Tom", "ada"

Invariant Culture算法的排序結果是: "ada", "Ada", "Tom"

Invariant Culture算法封裝了字母表,並且認為大寫字母所對應的小寫字母是相鄰的(aAbBcC…)。

Ordinal算法的排序結果是:"Ada", "Tom", "ada"

Ordinal算法里,大寫字母都在前面,小寫字母都在后面(A…Z,a…z)。

盡管Ordinal算法有一定限制,但是==運算符在進行string相等性比較的時候,總會考慮ordinal大小寫。實例版的string.Equals方法如果不傳參數的話,效果也是一樣,這就是string類型的默認的相等性比較行為。

Ordinal算法被string的==和Equals函數選擇,是因為它的高效和確定性。

下面這兩個方法可以設定是否考慮Culture和大小寫進行string比較:

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

靜態版本的方法優勢在於:如果兩個字符串有null的情況,那么仍然可以正常工作。

StringComparison有哪些值呢:

 

 下面我們來看幾個例子:

Console.WriteLine("Hello" == "hello" ); // False
Console.WriteLine(string.Equals("Hello", "hello", StringComparison.OrdinalIgnoreCase)); // True

Console.WriteLine("u" == "ü"); // False
Console.WriteLine(string.Equals("u", "ü", StringComparison.CurrentCulture)); // ?

 

string排序比較,string的示例方法是CompareTo,會執行culture相關的、大小寫相關的排序比較。與string的相等性比較不同,CompareTo沒有使用Ordinal比較算法,對於排序來說,Culture敏感的算法更有用。

方法的定義:

public int CompareTo(String strB);

CompareTo實例方法實現了泛型IComparable接口,該接口在.NET里面是一個標准的比較協議。

而對於其它類型的比較,可以使用靜態的Compare和CompareOrdinal方法。

 

所有的排序比較方法都會返回一個:正數/負數/0

第一個值在第二個值的后面,返回正數;第一個值在第二個值的前面,返回負數;兩個值並列,返回0。

Console.WriteLine("Base".CompareTo("Auto")); // 返回1
Console.WriteLine("Base".CompareTo("Base")); // 返回0
Console.WriteLine("Base".CompareTo("China")); // 返回-1
Console.WriteLine("base".CompareTo("Base")); // 返回-1
Console.WriteLine(string.Compare("base", "Base", true)); // 返回0

CultureInfo 對象

使用CultureInfo對象,就可以插入任何一個字母表

CultureInfo這個類是定義在System.Globalization命名空間下的

CultureInfo german = CultureInfo.GetCultureInfo("de-DE");
Console.WriteLine(string.Compare("Müller", "Muller", false, german)); // 返回結果是1

 

 

StringBuilder

StringBuilder類(System.Text命名空間)代表的是可編輯或者叫可改變的字符串

使用StringBuilder,你可以Append追加、Insert插入、Remove移除和Replace替換子字符串,而不用替換整個StringBuilder。

StringBuilder的構造函數可可以接收一個初始化的string值,以及內部容量的初始大小(默認是16字符)。如果超過了這個大小,StringBuilder會自動重新改變其內部結構的大小(輕微的性能損耗)以適應最大容量(默認是int.MaxValue)。

AppendLine,會執行Append動作,區別在於此操作會自定添加一個換行(Windows環境下是"\r\n")。

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("123");
stringBuilder.Append("456");
Console.WriteLine(stringBuilder.ToString()); // 結果為123456
stringBuilder.AppendLine("789");
Console.WriteLine(stringBuilder.ToString()); // 結果是123456789后面換行了
stringBuilder.AppendLine("abc");
Console.WriteLine(stringBuilder.ToString());

AppendFormat,接收一個復合格式字符串,和string.Format一樣。

StringBuilder還有一個Length屬性,獲取長度的屬性。

StringBuilder還有一個索引器,用來讀取每個字符的可寫的索引器。

想要清除StringBuilder的內容,可以初始化一個新的StringBuilder,或者把Length屬性設為0。但是把StringBuilder的Length屬性設為0並沒有縮小它的容量,它占用的內存大小是不變的,想要釋放內容,必須要new一個,而且要保證原來的實例可以被GC。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM