C#字串

sunlei8311發表於2007-12-28
無論使用何種型別的資料,也無論建立何種型別的應用程式,幾乎毫無疑問地都要用到字串。不管程式中的資料採用什麼方式儲存,對終端使用者來說,他們只能理解人可讀的文字資料。正因為如此,瞭解如何處理字串,是每一位需要建立豐富和令人信服的應用程式的開發者都要掌握的基礎知識。
除了介紹如何處理.NET框架中的字串以外,這一章還將介紹正規表示式。正規表示式是格式化的程式碼段,它可用來驗證一個字串是否與給定的格式相匹配,並且可用於從表面上看來是自由文字的符號串中,抽取有意義的資訊,例如從使用者的輸入字串中抽取姓名,從輸入的電話號碼中抽取地區程式碼,或者從一個給定的URL字串中抽取主機名等。
3.1 字串
正確處理字串是編寫高質量應用程式所需要的基本技能。即使要處理的是數字訊號或影象資料,終端使用者也需要文字形式的資訊反饋。本節將介紹.NET框架中的字串,包括如何格式化字串,如何操縱字串,如何比較字串,以及其他有用的字串操作。
3.1.1 .NET框架中的字串
在.NET框架和公共語言執行時(CLR)出現之前,開發者要在字串的處理上耗費相當多的程式設計工作量。事實上,一個可重用的字串例程庫,是每一位C/C++程式設計師必備的程式設計工具箱。在不同的程式語言之間編寫交換字串資料的程式碼是困難的。例如,在Pascal語言中,字串是一個儲存於記憶體中的陣列,陣列的第一個元素指明瞭字串的長度。而在C語言中,字串是一個儲存於記憶體中的可變長的陣列,該陣列的結束以ASCII字元null表示(在C語言中可用‘/0’表示)。
在.NET框架中,從儲存結構上講,字串是不可變的值。這意味著當你用C#語言(或.NET 支援的任何其他語言)建立了一個字串之後,字串被儲存於一個定長的結構中,以使CLR 的某些部分有更快的執行速度(本書的第16章將介紹與此有關的內容)。因此,當執行諸如字串的比較操作,或者修改字串中的某個字元時,CLR實際上為這個字串建立了多個拷貝。
在C#中,字串的宣告與整數型別、浮點數型別的宣告語法相同,如下面的程式碼段所示:
string x = "Hello World";
string y;
string z = x;
3.1.2 格式化字串
在處理字串時,一個常見的任務是對字串格式化。當顯示資訊給使用者時,經常需要顯示諸如日期、時間、數字值、小數、貨幣值,甚至十六進位制數值。C#中的字串都具有顯示這些資訊型別及更多資訊型別的能力。C#中的字串的另一個強大特徵是,如果使用標準的格式化工具,所輸出的結果將具有本地意識。例如,如果程式為一個英國使用者顯示當前日期的一個縮寫,那麼對於一個美國使用者,它顯示的是符合美國使用者習慣的另一個不同的日期縮寫。
要建立一個格式化的字串,所要做的是呼叫string類的format方法,並給該方法傳遞一個格式字串作為引數,如下面一行程式碼所示:
string formatted = string.Format("The value is {0}", value);
佔位符{0}指出value的輸出值應該插入的位置。除了描述輸出值的插入位置外,還可以指定輸出值的輸出格式。
通過使用定製的格式描述符,還可以將其他型別的資料轉換為字串。例如,下列語句用於將DataTime資料型別轉換為一個定製的字串:
DateTime.ToString("format specifiers");
表3.1列出了用於日期、時間、數字值和其他常用資料型別的格式描述符。
表3.1 DataTime型別定製的格式描述符
描述符
含義
d
顯示一個月內的當前一天
dd
顯示一個月內的當前一天,如果天的數值小於10,則前面補0
ddd
顯示星期幾的三字元縮寫
dddd (+)
根據給定的Datatime值,顯示星期幾的全名
f (+)
顯示秒數的最有效位,格式描述符中的f越多,有效位數就越多,這裡的秒數
指的是累計時間的秒數,不是從最近的一分種開始計算的秒數
F (+)
與f (+)相同,不同之處是不顯示結尾的0
g
顯示給定DataTime值的紀元(例如“A.D.”)
h
顯示小時數,顯示範圍為1~12
hh
顯示小時數,顯示範圍為1~12,如果小時數小於10,前面補0
H
顯示小時數,顯示範圍為0~23
HH
顯示小時數,顯示範圍為0~23,如果小時數小於10,前面補0
m
顯示分數,顯示範圍為0~59
mm
顯示分數,顯示範圍為0~59,如果分數小於10,前面補0
M
顯示月份數,顯示範圍為1~12
MM
顯示月份數,顯示範圍為1~12,如果月份數小於10,前面補0
MMM
顯示月份的三字元英文縮寫
MMMM
顯示月份的全英文名
s
顯示秒數,顯示範圍為0~59
ss (+)
顯示秒數,顯示範圍為0~59,如果秒數小於10,前面補0
t
對一個給定的時間,顯示AM/PM的首字元
tt (+)
對一個給定的時間,顯示AM/PM的全名
y/yy/yyy
對一個給定的時間,顯示它的年份
z/zz/zzz (+)
對一個給定的時間,顯示時區
看看下面的幾行程式碼,這段程式碼演示瞭如何使用字串的格式描述符來建立定製格式的日期和時間字串:
DateTime dt = DateTime.Now;
Console.WriteLine(string.Format("Default format: {0}", dt.ToString()));
Console.WriteLine(dt.ToString("dddd dd MMMM, yyyy g"));
Console.WriteLine(string.Format("Custom Format 1: {0:MM/dd/yy hh:mm:sstt}", dt));
Console.WriteLine(string.Format("Custom Format 2: {0:hh:mm:sstt G//MT zz}", dt));
上面的程式碼段執行後,將產生如下的輸出結果:
Default format: 9/24/2005 12:59:49 PM
Saturday 24 September, 2005 A.D.
Custom Format 1: 09/24/05 12:59:49PM
Custom Format 2: 12:59:49PM GMT -06
對於數字值,也可以應用定製的格式描述符。表3.2列出了可用於數字值的定製的格式描述符。
表3.2 定製的數字值格式描述符

描述符    含義
0 零佔位符

#
數字佔位符,如果給定的值中有某一位處在由#指出的位置,那麼該位將
顯示在格式化輸出中
.
十進位制點
,
千位分隔符
%
百分率描述符,被格式化的值在輸出之前乘以100
E0/E+0/e/e+0/e0/E
科學計數法
'XX' 或"XX"
字面值,它們直接包含在格式化輸出中,不經過相對位置的變換
;
負數、零和正數之間的條件分隔符
如果在格式字串中定義了多個格式段,則可實現對數字值的輸出格式的更細粒度的條件邏輯控制:
          ? 兩個格式段—如果有兩個格式段,那麼第一段應用於所有的正數值(含0);第二段應用於負數值,當需要用圓括號將負數值括起來時,這是極為有用的,許多賬目管理軟體包有這樣的要求。
          ? 三個格式段—如果有三個格式段,那麼第一段應用於所有的正數值(不含0);第二段
應用於負數值;第三段應用於0。下面的幾行程式碼舉例說明了如何使用定製的數字格式描述符:
double dVal = 59.99;
double dNeg = -569.99;
double zeroVal = 0.0;
double pct = 0.23;
string formatString = "{0:$#,###0.00;($#,###0.00);nuttin}";
Console.WriteLine(string.Format(formatString, dVal));
Console.WriteLine(string.Format(formatString, dNeg));
Console.WriteLine(string.Format(formatString, zeroVal));
Console.WriteLine(pct.ToString("00%"));
以上程式碼產生下列輸出結果:
$59.99
($569.99)
nuttin
23%
3.1.3 操縱和比較字串
除了將各種型別的資料用不同的格式輸出外,另一個與字串有關的常見程式設計任務,是對字串進行操縱和比較。字串型別在底層的.NET框架的基礎類庫中實質上是一個類,記住這一點很重要。因為字串型別是一個類,因此在程式中就可以呼叫它的方法,就像呼叫任何其他類的方法一樣。
在呼叫字串的方法時,既可以對字串的字面值呼叫它的方法,也可以對字串變數呼叫它的方法,如下面的程式碼所示:
int x = string.Length();
int y = "Hello World".Length();
表3.3簡要描述了可用於獲得字串內部資訊或對其進行操縱的常用方法。

表3.3 字串例項物件的常用方法
方  法
說  明
CompareTo
比較兩個字串
Contains
返回一個布林值,判斷當前的字串是否包含一個指定的子串
CopyTo
將一個字串的子串拷貝至一個字元陣列的指定位置
EndsWith
返回一個布林值,判斷當前字串是否以一個指定的子串為結尾
Equals
判斷一個字串與另一個字串是否相等,與‘= =’操作符的功能相同
IndexOf
返回在當前字串中出現的一個指定子串的下標
IndexOfAny
返回在當前字串的一個指定子串中,任何一個字元首次出現的位置下標
PadLeft
在當前字串的頭部填補空白符或其他Unicode字元,使字串右對齊
PadRight
在當前字串的末尾填補空白符或其他Unicode字元,使字串左對齊
Remove
從當前字串中刪除指定數量的字元
Replace
將當前字串中出現的指定字元或字串替換為另一個指定的字元或字串
Split
將當前的字串拆分為一個字串的陣列,以指定的字元為拆分點
StartsWith
返回一個布林值,表明該字串是否以一個指定的子串開始
SubString
以開始點的位置和長度為引數,返回一個字串的指定子串
ToCharArray
將字串轉換為一個字元陣列
ToLower
將字串中的所有字元轉換為小寫
ToUpper
將字串中的所有字元轉換為大寫
Trim
刪除從字串首部到尾部中出現的一個給定的符號集合
TrimStart
執行Trim操作,但是隻刪除首部出現的一個給定的符號集合
TrimEnd
執行Trim操作,但是隻刪除尾部出現的一個給定的符號集合
看看下面的一段程式碼示例,這段程式展示瞭如何查詢字串的資訊和操縱字串:
string sourceString = "Mary Had a Little Lamb";
string sourceString2 = " Mary Had a Little Lamb ";
Console.WriteLine(sourceString.ToLower());
Console.WriteLine(string.Format("The string '{0}' is {1} chars long.",
sourceString,sourceString.Length));
Console.WriteLine(string.Format("Fourth word in sentence is : {0}",
sourceString.Split(' ')[3]));
Console.WriteLine(sourceString2.Trim());
Console.WriteLine("Two strings equal? " + (sourceString == sourceString2.Trim()));
上述程式碼產生如下的輸出:
mary had a little lamb
The string 'Mary Had a Little Lamb' is 22 chars long.
Fourth word in sentence is : Little
Mary Had a Little Lamb
Two strings equal? True
3.1.4 StringBuilder類介紹
前面提到過,字串在記憶體中是不可變的。這意味著,如果為了得到第三個字串而連線兩個字串時,在一個短暫的時間內,CLR將會在記憶體中維護三個字串的例項。比方說,假設你編寫了如下的程式碼用於連線字串:
string a = "Hello";
string b = "World";
string c = a + " " + c;
上面的程式碼在執行時實際存在四個字串,包括它們佔用的儲存空間。為了緩解這種因字串連線而帶來的效能問題,同時為了給字串連線操作給予程式設計工具支援,.NET框架提供了一個名為StringBuilder的類。
通過使用StringBuilder類來動態建立可變長字串,可以避免因CLR中的字串的不可變性而帶來的問題,如此編寫的程式碼通常會更容易閱讀。讓我們來看一看StringBuilder類在下面的程式碼中是如何發揮功能的:
StringBuilder sb = new StringBuilder();
sb.Append("Greetings!/n");
formatString = "{0:$#,###0.00;($#,###0.00);Zero}";
dVal = 129.99;
sb.AppendFormat(formatString, dVal);
sb.Append("/nThis is a big concatenated string.");
Console.WriteLine(sb.ToString());
上面的程式產生的輸出結果為:
Greetings!
$129.99
This is a big concatenated string.
注意,在上面的程式示例中,/n的作用是在輸出的字串中插入一個換行符。 

相關文章