版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第8章 字符串和正則表達式在本書的第一部分,我們一直在使用字符串,并說明C#中string關鍵字的映射實際上指向.NET 基類System.String。System.String是一個功能非常強大且用途非常廣泛的基類,但它不是.NET中惟一與字符串相關的類。本章首先復習一下System.String的特性,再介紹如何使用其他的.NET類來處理字符串,特別是System.Text 和 System.Text.RegularExpressions命名空間中的類。本章主要介紹下述內容: 創(chuàng)建字符串:如果多次修改一個字符串,例如,在顯示字符串或將其傳遞給其他方法或應用程序前,創(chuàng)建一個較長的字符串,S
2、tring類就會變得效率低下。對于這種情況,應使用另一個類System.Text.StringBuilder,因為它是專門為這種情況設計的。 格式化表達式:這些表達式將用于后面幾章中的Console.WriteLine() 方法。格式化表達式使用兩個有效的接口IFormatProvider和IFormattable來處理。在自己的類上執(zhí)行這兩個接口,就可以定義自己的格式化序列,這樣,Console.WriteLine()和類似的類就可以以指定的方式顯示類的值。 正則表達式:.NET還提供了一些非常復雜的類來識別字符串,或從長字符串中提取滿足某些比較復雜條件的子字符串。例如,找出字符串中重復出現(xiàn)
3、的某個字符或一組字符,或者找出以s開頭、且至少包含一個n的所有單詞,或者找出遵循雇員ID或社會安全號碼約定的字符串。雖然可以使用字符串類,編寫方法來執(zhí)行這類處理,但這類方法編寫起來比較繁瑣,而使用System.Text.RegularExpressions命名空間中的類就比較簡單,System.Text.RegularExpressions專門用于執(zhí)行這類處理。8.1 System.String類在介紹其他字符串類之前,先快速復習一下String類上一些可利用的方法。System.String是一個類,該類專門用于存儲字符串,允許對字符串進行許多操作。由于這種數(shù)據(jù)類型非常重要,C#提供了它自己
4、的關鍵字和相關的語法,以便使用這個類來很容易地處理字符串。使用運算符重載可以連接字符串:string message1 = "Hello" /return "Hello"message1 += ", There" / return "Hello, There "string message2 = message1 + "!" / return "Hello, There!"C#還允許使用類似于索引符的語法來提取指定的字符:char char4 = message4; / re
5、turns 'a'. Note the char is zero-indexed這個類可以完成許多常見的任務,例如替換字符、刪除空白和把字母變成大寫形式等??捎玫姆椒ㄈ绫?-1所示。表 8-1方 法作 用Compare比較字符串的內容,考慮文化背景(場所),確定某些字符是否相等CompareOrdinal與Compare一樣,但不考慮文化背景Format格式化包含各種值的字符串和如何格式化每個值的說明符IndexOf定位字符串中第一次出現(xiàn)某個給定子字符串或字符的位置IndexOfAny定位字符串中第一次出現(xiàn)某個字符或一組字符的位置LastIndexOf與IndexOf一樣,但定
6、位最后一次出現(xiàn)的位置 LastIndexOfAny與IndexOfAny,但定位最后一次出現(xiàn)的位置PadLeft在字符串的開頭,通過添加指定的重復字符填充字符串PadRight在字符串的結尾,通過添加指定的重復字符填充字符串Replace用另一個字符或子字符串替換字符串中給定的字符或子字符串Split在出現(xiàn)給定字符的地方,把字符串拆分為一個子字符串數(shù)組Substring在字符串中獲取給定位置的子字符串ToLower把字符串轉換為小寫形式ToUpper把字符串轉換為大寫形式Trim刪除首尾的空白注意:這個表并不完整,但可以讓您明白字符串所提供的功能。8.1.1 創(chuàng)建字符串如上所述,string類
7、是一個功能非常強大的類,它執(zhí)行許多很有用的方法。但是,string類存在一個問題:重復修改給定的字符串,效率會很低,它實際上是一個不可變的數(shù)據(jù)類型,一旦對字符串對象進行了初始化,該字符串對象就不能改變了。修改字符串內容的方法和運算符實際上是創(chuàng)建一個新的字符串,如果必要,可以把舊字符串的內容復制到新字符串中。例如,下面的代碼:string greetingText = "Hello from all the guys at Wrox Press. "greetingText += "We do hope you enjoy this book as much as
8、we enjoyed writing it."在執(zhí)行這段代碼時,首先,創(chuàng)建一個System.String類型的對象,并初始化為文本“Hello from all the people at Wrox Press. ”。注意該行最后的空格。此時.NET 運行庫會為該字符串分配足夠的內存來保存這個文本(39個字符),再設置變量greetingText,表示這個字符串實例。從語法上看,下一行代碼是把更多的文本添加到字符串中。實際上并非如此,而是創(chuàng)建一個新字符串實例,給它分配足夠的內存,以保存合并起來的文本(共103個字符)。最初的文本“Hello from all the people a
9、t Wrox Press. ”復制到這個新字符串中,再加上額外的文本“We do hope you enjoy this book as much as we enjoyed writing it”。然后更新存儲在變量greetingText中的地址,使變量正確地指向新的字符串對象。舊的字符串對象被撤銷了引用不再有變量引用它,下一次垃圾收集器清理應用程序中所有未使用的對象時,就會刪除它。這本身還不壞,但假定要對這個字符串加密,在字母表中,用ASCII碼中的字符替代其中的每個字母(標點符號除外),以便以后作為非常簡單的加密模式的一部分,就會把該字符串變成“Ifmmp gspn bmm uif h
10、vst bu Xspy Qsftt. Xf ep ipqf zpv fokpz uijt cppl bt nvdi bt xf fokpzfe xsjujoh ju.”。完成這個任務有好幾種方式,但最簡單、最高效的一種(假定只使用String類)是使用String.Replace()方法,把字符串中指定的子字符串用另一個子字符串代替。使用Replace(),加密文本的代碼如下所示:string greetingText = "Hello from all the guys at Wrox Press. "greetingText += "We do hope yo
11、u enjoy this book as much as we enjoyed writing it."for(int i = (int)'z' i>=(int)'a' ; i) char old1 = (char)i; char new1 = (char)(i+1); greetingText = greetingText.Replace(old1, new1);for(int i = (int)'Z' i>=(int)'A' ; i) char old1 = (char)i; char new1 = (c
12、har)(i+1); greetingText = greetingText.Replace(old1, new1);Console.WriteLine("Encoded:n" + greetingText);注意:為了簡單起見,這段代碼沒有把Z換成A,或把z換成a。這些字符分別編碼為和。Replace()以一種智能化的方式工作,在某種程度上,它并沒有實際創(chuàng)建一個新字符串,除非要對舊字符串進行某些改變。原來的字符串包含23個不同的小寫字母,和3個不同的大寫字母。所以Replace()就分配一個新字符串,共26次,每個新字符串都包含103個字符。因此加密過程需要在堆上有一個能
13、存儲總共2678個字符的字符串對象,最終將等待被垃圾收集!顯然,如果使用字符串進行文字處理,應用程序就會有嚴重的性能問題。為了解決這個問題,Microsoft提供了System.Text.StringBuilder類。StringBuilder不像String功能那么強大,后者已有那么多所支持的方法。在StringBuilder上可以進行的處理僅限于替換和添加或刪除字符串中的文本。但是,它的工作方式非常高效。在構造一個字符串時,要給它分配足夠的內存來保存字符串,但StringBuilder通常分配的內存會比需要的更多??梢赃x擇顯式指定要分配多少內存,但如果沒有顯式指定,存儲單元量在默認情況下就
14、根據(jù)StringBuilder初始化時的字符串長度來確定。它有兩個主要的屬性: Length指定字符串的實際長度; Capacity是字符串占據(jù)存儲單元的長度。對字符串的修改就在賦予StringBuilder實例的存儲單元中進行,這就大大提高了添加子字符串和替換單個字符的效率。刪除或插入子字符串仍然效率低下,因為這需要移動隨后的字符串。只有執(zhí)行擴展字符串容量的操作,才會給字符串分配需要的新內存,才可能移動整個包含的字符串。在編寫本書的過程中,Microsoft并沒有說明會添加多少額外的容量,但從經(jīng)驗來看,StringBuilder如果檢測到容量超出,且該容量中沒有顯示設置新值,就會使自己的容量
15、翻倍。例如,如果使用StringBuilder對象構造最初的歡迎字符串,可以編寫下面的代碼:StringBuilder greetingBuilder = new StringBuilder("Hello from all the guys at Wrox Press. ", 150);greetingBuilder.Append("We do hope you enjoy this book as much as we enjoyed writing it"); 注意:為了使用StringBuilder類,需要在代碼中引用System.Text。在這段
16、代碼中,為StringBuilder設置的初始容量是150。最好把容量設置為字符串可能的最大長度,確保StringBuilder不需要重新分配內存,因為其容量足夠用了。理論上,可以設置盡可能大的數(shù)字,足夠給該容量傳送一個int,但如果實際上給字符串分配20億個字符的空間(這是StringBuilder實例允許擁有的最大理論空間),系統(tǒng)就可能會沒有足夠的內存。執(zhí)行上面的代碼,首先創(chuàng)建一個StringBuilder對象,如圖8-1所示。圖 8-1在調用Append()方法時,其他文本就放在空的空間中,不需要分配更多的內存。但是,多次替換文本才能獲得使用StringBuilder所帶來的性能提高。例
17、如,如果要以前面的方式加密文本,就可以執(zhí)行整個加密過程,無須分配更多的內存:StringBuilder greetingBuilder = new StringBuilder("Hello from all the guys at Wrox Press. ", 150);greetingBuilder.Append("We do hope you enjoy this book as much as we enjoyed writing it"); for(int i = (int)'z' i>=(int)'a' ;
18、 i-) char old1 = (char)i; char new1 = (char)(i+1); greetingBuilder = greetingBuilder.Replace(old1, new1);for(int i = (int)'Z' i>=(int)'A' ; i ) char old1 = (char)i; char new1 = (char)(i+1); greetingBuilder = greetingBuilder.Replace(old1, new1);Console.WriteLine("Encoded:n&quo
19、t; + greetingBuilder.ToString();這段代碼使用了StringBuilder.Replace()方法,它的功能與String.Replace()一樣,但不需要在過程中復制字符串。在上述代碼中,為存儲字符串而分配的總存儲單元是150個字符,用于StringBuilder實例以及在最后一個Console.WriteLine()語句中內部執(zhí)行字符串操作期間分配的內存。一般,使用StringBuilder就可以執(zhí)行字符串的任何操作,String可以用于存儲字符串或顯示最終結果等。StringBuilder成員前面介紹了StringBuilder的一個構造函數(shù),它的參數(shù)是一個
20、初始字符串及該字符串的容量。還有幾個其他的StringBuilder構造函數(shù),在這些StringBuilder構造函數(shù)中,只能提供一個字 符串:StringBuilder sb = new StringBuilder("Hello");或者用給定的容量創(chuàng)建一個空的StringBuilder:StringBuilder sb = new StringBuilder(20);除了前面介紹的Length 和 Capacity屬性外,還有一個只讀屬性MaxCapacity,它表示對給定的StringBuilder實例的限制,最多可以有多少容量。在默認情況下,這由int.MaxVal
21、ue給定(大約20億,如前所述),在構造StringBuilder對象時,也可以把這個值設置為較低的值:/ This will both set initial capacity to 100, but the max will be 500./ Hence, this StringBuilder can never grow to more than 500 characters,/ otherwise it will raise exception if you try to do that.StringBuilder sb = new StringBuilder(100, 500);還可
22、以隨時顯式地設置容量,但如果把這個值設置為低于字符串的當前長度,或者超出了最大容量,就會拋出一個異常:StringBuilder sb = new StringBuilder("Hello");sb.Capacity = 100;主要的StringBuilder方法如表8-2所示。 表 8-2名 稱作 用Append()給當前字符串添加一個字符串AppendFormat()添加特定格式的字符串Insert()在當前字符串中插入一個子字符串Remove()從當前字符串中刪除字符Replace()在當前字符串中,用另一個字符替換某個字符,或者用當前字符串中的另一個子字符串替換某
23、個字符串ToString()把當前字符串轉換為System.String對象(在System.Object中被重寫)其中一些方法還有幾種格式的重載方法。注意:AppendFormat()實際上會在調用Console.WriteLine()時調用,它負責確定所有像0:D的格式化表達式應使用什么表達式替代。下一節(jié)討論這個問題。不能把StringBuilder轉換為String(隱式轉換和顯式轉換都不行)。如果要把StringBuilder的內容輸出為String,惟一的方式是使用ToString()方法。8.1.2 格式化字符串前面的代碼示例中編寫了許多類和結構,對這些類和結構執(zhí)行ToString
24、()方法,都是為了能顯示給定變量的內容。但是,用戶常常希望以各種可能的方式顯示變量的內容,在不同的文化或地區(qū)背景中有不同的格式。.NET基類System.DateTime就是最明顯的一個示例:可以把日期顯示為14 February 2002、14 Feb 2002、2/14/02(美國)、14/2/02(英國)或14. February 2002(德國)。同樣,對于第3章中編寫的Vector結構,執(zhí)行Vector.ToString()方法,是為了以(4, 56, 8)格式顯示矢量。編寫矢量的另一個非常常用的方式是4i + 56j + 8k。如果要使類的用戶友好性比較高,就需要使用某些工具以用戶
25、希望使用的方式顯示它們的字符串表示。.NET運行庫定義了一種標準方式:使用一個接口IFormattable,本節(jié)的主題就是說明如何把這個重要特性添加到類和結構上。在顯示一個變量時,常常需要指定它的格式,此時我們經(jīng)常調用Console.WriteLine()方法。因此,我們把這個方法作為示例,但這里的討論適用于格式化字符串的大多數(shù)情況。例如,如果要在列表框或文本框中顯示一個變量的值,一般要使用String.Format()方法來獲得該變量的合適字符串表示,但實際上所用的格式說明符所需的格式與傳遞給Console.WriteLine()的格式相同,因此本節(jié)把Console.WriteLine()作
26、為一個示例來說明。首先看看在為基本類型提供格式字符串時會發(fā)生什么,再看看如何把自己的類和結構的格式說明符拖動到過程中。第2章在Console.Write()和 Console.WriteLine()中使用了格式字符串:double d = 13.45;int i = 45;Console.WriteLine("The double is 0,10:E and the int contains 1", d, i);格式字符串本身大都由要顯示的文本組成,但只要有要格式化的變量,它在參數(shù)列表中的下標就必須放在括號中。在括號中還可以有與該項目的格式相關的其他信息,例如可以包含: 該
27、項目要占用的字符數(shù),這個信息的前面應有一個逗號,負值表示該項目應左對齊,正值表示該項目應右對齊。如果該項目占用的字符數(shù)比給定的多,其內容也會完整地顯示出來。 格式說明符也可以顯示出來。它的前面應有一個冒號,表示應如何格式化該項目。例如,把一個數(shù)字格式化為貨幣,或者以科學計數(shù)法顯示。第2章簡要介紹了數(shù)字類型的常見格式說明符,表8-3再次引用該表。表 8-3格式符應 用含 義示 例C數(shù)字類型 專用場合的貨幣值$4834.50 (USA)£4834.50 (UK)D只用于整數(shù)類型一般的整數(shù)4834E數(shù)字類型科學計數(shù)法4.834E+003F數(shù)字類型小數(shù)點后的位數(shù)固定4384.50G數(shù)字類型一
28、般的數(shù)字4384.5N數(shù)字類型通常是專用場合的數(shù)字 格式4,384.50 (UK/USA)4 384,50 (歐洲大陸)P數(shù)字類型百分比計數(shù)法432,000.00%X只用于整數(shù)類型16進制格式1120 (如果要顯示0x1120,需要寫上0x)如果要在整數(shù)上添加前導0,可以使用格式說明符0重復指定所需的次數(shù)。例如,格式說明符0000會把3顯示為0003,99顯示為0099。這里不能給出完整的列表,因為其他數(shù)據(jù)類型有自己的格式說明符。本節(jié)的主要目的是說明如何為自己的類定義格式說明符。1. 字符串的格式化作為如何格式化字符串的一個示例,看看執(zhí)行下面的語句會得到什么結果:Console.WriteLi
29、ne("The double is 0,10:E and the int contains 1", d, i);Console.WriteLine()只是把參數(shù)的完整列表傳送給靜態(tài)方法String.Format(),如果要在字符串中以其他方式格式化這些值,例如顯示在一個文本框中,也可以調用這個方法。帶有3個參數(shù)的WriteLine()重載方法的執(zhí)行方式如下:/ Likely implementation of Console.WriteLine()public void WriteLine(string format, object arg0, object arg1) C
30、onsole.WriteLine(string.Format(format, arg0, arg1);上面的代碼依次調用了帶有1個參數(shù)的重載方法WriteLine(),僅顯示了傳遞過來的字符串的內容,沒有對它進行進一步的格式化。String.Format()現(xiàn)在需要用對應對象的合適字符串表示來替換每個格式說明符,構造最終的字符串。但是,如前所述,對于這個建立字符串的過程,需要StringBuilder實例,而不是字符串實例。在這個示例中,StringBuilder實例是用字符串的第一部分(即文本“The double is”)創(chuàng)建和初始化的。然后調用StringBuilder.AppendFo
31、rmat()方法,傳遞第一個格式說明符“0,10:E”和相應的對象double,把這個對象的字符串表示添加到構造好的字符串中,這個過程會繼續(xù)重復調用StringBuilder.Append() 和 StringBuilder.AppendFormat()方法,直到得到了全部格式化好的字符串為止。下面的內容比較有趣。因為StringBuilder.AppendFormat()需要指出如何格式化對象,所以它做的第一件事是檢查對象,確定它是否執(zhí)行System命名空間中的接口IFormattable。試著把這個對象轉換為接口,會發(fā)現(xiàn)轉換很容易成功,或者使用C#關鍵字is,也能實現(xiàn)此轉換。如果轉換失敗,
32、AppendFormat()只會調用對象的ToString()方法,其中所有的對象都繼承了System.Object或被重寫。在前面給出的編寫各種類和結構的示例中,執(zhí)行過程都是這樣,因為我們編寫的類都沒有執(zhí)行這個接口。這就是在前面的章節(jié)中,Object.ToString()的重寫方法允許在Console.WriteLine()語句中顯示類和結構如Vector的原因。但是,所有預定義的基本數(shù)字類型都執(zhí)行這個接口,對于這些類型,特別是這個示例中的double和int,就不會調用繼承了System.Object的基本ToString()方法。為了理解這個過程,需要了解IFormattable接口。I
33、Formattable只定義了一個方法,該方法也叫作ToString(),它帶有兩個參數(shù),這與System. Object版本的ToString()不同,它不帶參數(shù)。下面是IFormattable的定義:interface IFormattable string ToString(string format, IFormatProvider formatProvider);這個ToString()重載方法的第一個參數(shù)是一個字符串,它指定要求的格式。換言之,它是字符串的說明符部分,放在字符串的中,該參數(shù)最初傳遞給Console.WriteLine()或 String. Format()。例如,在
34、本例中,最初的語句如下:Console.WriteLine("The double is 0,10:E and the int contains 1", d, i);在計算第一個說明符0,10:E時,在double變量d上調用這個重載方法,傳遞給它的第一個參數(shù)是"E"。StringBuilder.AppendFormat()傳遞的總是顯示在原始字符串的合適格式說明符內冒號后面的文本。本書不討論ToString()的第2個參數(shù),它是執(zhí)行接口IFormatProvider的對象引用。這個接口提供了ToString()在格式化對象時需要考慮的更多信息 一般包括
35、文化背景信息(.NET文化背景類似于Windows的背景,如果格式化貨幣或日期,就需要這些信息)。如果直接從源代碼中調用這個ToString()重載方法,就需要提供這樣一個對象。但StringBuilder.AppendFormat()為這個參數(shù)傳遞一個空值。如果formatProvider為空,ToString()就要使用系統(tǒng)設置中指定的文化背景信息?,F(xiàn)在回過頭來看看本例。第一個要格式化的項目是double,對此要求使用指數(shù)計數(shù)法,格式說明符為E。如前所述,StringBuilder.AppendFormat()方法會建立執(zhí)行IFormattable接口的對象double,因此要調用帶有兩個
36、參數(shù)的ToString()重載方法,其第一個參數(shù)是字符串“E”。第二個參數(shù)為空?,F(xiàn)在double的這個方法在執(zhí)行時,會考慮要求的格式和當前的文化背景,以合適的格式返回double的字符串表示。StringBuilder.AppendFormat()則按照需要在返回的字符串中添加前導空格,使之共有10個字符。下一個要格式化的對象是int,它不需要任何特殊的格式 (格式說明符是1)。由于沒有格式要求,StringBuilder.AppendFormat()會給該格式字符串傳遞一個空引用,并適當?shù)仨憫獛в袃蓚€參數(shù)的int.ToString()重載方法,由于沒有特殊的格式要求,所以也可以調用不帶參數(shù)的
37、ToString()方法。整個過程如圖8-2所示。圖 8-22. FormattableVector示例前面介紹了如何構造格式字符串,下面擴展本書前面的Vector示例,以多種方式格式化矢量。這個示例的代碼可以從上下載。只要理解了所涉及到的規(guī)則,實際上編寫代碼就相當簡單了。我們只需要實現(xiàn)IFormattable,提供由該接口定義的ToString()重載方法 即可。要提供的格式說明符如下: N 應解釋為一個請求,以提供一個數(shù)字,即矢量的模,它是其成員的平方和,在數(shù)學上等于Vector的長度的平方,通常放在兩個豎杠的中間:|34.5|。 VE 應解釋為以科學計數(shù)法顯示每個成員的一個請求,就像說明
38、符E應用于double,就可以表示為 (2.3E+01, 4.5E+02, 1.0E+00)。 IJK應解釋為以格式23i + 450j + 1k顯示矢量的一個請求。 其他內容應僅返回Vector的默認表示方法 (23, 450, 1.0)。為了簡單起見,我們不以IJK和科學計數(shù)法的格式執(zhí)行任何選項以顯示矢量,而是以不區(qū)分大小寫的方式來測試說明符,允許使用ijk和IJK。注意,使用什么字符串表示格式說明符完全取決于用戶。為此,首先修改Vector的聲明,使之執(zhí)行IFormattable:struct Vector : IFormattable public double x, y, z;下面添
39、加帶有2個參數(shù)的ToString()重載的實現(xiàn):public string ToString(string format, IFormatProvider formatProvider) if (format = null) return ToString(); string formatUpper = format.ToUpper(); switch (formatUpper) case "N": return "| " + Norm().ToString() + " |" case "VE": return S
40、tring.Format("( 0:E, 1:E, 2:E )", x, y, z); case "IJK": StringBuilder sb = new StringBuilder(x.ToString(), 30); sb.Append(" i + "); sb.Append(y.ToString(); sb.Append(" j + "); sb.Append(z.ToString(); sb.Append(" k"); return sb.ToString(); default: re
41、turn ToString(); 這就是我們需要編寫的代碼。注意在調用任何方法前,應防止使用格式字符串為空的參數(shù)。我們希望這個方法盡可能健壯,所有基本類型的格式說明符都是不區(qū)分大小寫的,其他開發(fā)人員也希望能使用我們的類。對于格式說明符VE,需要把每個成員格式化為科學計數(shù)法,所以再次使用String.Format ()方法。字段x、y和z都是double類型。對于IJK格式限定符,把幾個子字符串添加到字符串中,使用StringBuilder對象來提高性能。為了保證完整,也可以再次使用前面開發(fā)的無參數(shù)的ToString()重載方法:public override string ToString()
42、 return "( " + x + " , " + y + " , " + z + " )" 最后,需要添加一個Norm()方法,計算矢量的平方(模),因為在開發(fā)Vector結構時,沒有提供這個方法:public double Norm() return x*x + y*y + z*z;下面用一些合適的測試代碼測試可格式化的矢量:static void Main() Vector v1 = new Vector(1,32,5); Vector v2 = new Vector(845.4, 54.3, 7.8);
43、Console.WriteLine("nIn IJK format,nv1 is 0,30:IJKnv2 is 1,30:IJK", v1, v2); Console.WriteLine("nIn default format,nv1 is 0,30nv2 is 1,30", v1, v2); Console.WriteLine("nIn VE formatnv1 is 0,30:VEnv2 is 1,30:VE", v1, v2); Console.WriteLine("nNorms are:nv1 is 0,20:Nnv
44、2 is 1,20:N", v1, v2);運行這個示例的結果如下所示:FormattableVectorIn IJK format,v1 is 1 i + 32 j + 5 kv2 is 845.4 i + 54.3 j + -7.8 kIn default format,v1 is ( 1 , 32 , 5 )v2 is ( 845.4 , 54.3 , -7.8 )In VE formatv1 is ( 1.000000E+000, 3.200000E+001, 5.000000E+000 )v2 is ( 8.454000E+002, 5.430000E+001,7.8000
45、00E+000 )Norms are:v1 is | 1050 |v2 is | 717710.49 |這說明了選用的定制格式說明符是正確的。8.2 正則表達式正則表達式在各種程序中都有著難以置信的作用,但并不是所有的開發(fā)人員都知道這一點。正則表達式被當作一種有特定功能的小型編程語言:在大的字符串表達式中定位一個子字符串。它不是一種新技術,最初它是在UNIX環(huán)境中開發(fā)的,與Perl一起使用得比較多。Microsoft把它移植到Windows中,到目前為止在腳本語言中用得比較多。但System.Text.Regular- Expressions命名空間中的許多.NET類都支持正則表達式。許多您都
46、不太熟悉正則表達式語言,所以本節(jié)將主要解釋正則表達式和相關的.NET類。如果您很熟悉正則表達式,就可以跳過本節(jié),學習.NET基類的引用。注意,.NET正則表達式引擎是為兼容Perl 5的正則表達式設計的,但有一些新特性。8.2.1 正則表達式概述正則表達式語言是一種專門用于字符串處理的語言。它包含兩個功能: 一組用于標識字符類型的轉義代碼。您可能很熟悉DOS表達式中的*字符表示任意子字符串(例如,DOS命令Dir Re*會列出所有名稱以Re開頭的文件)。正則表達式使用與*類似的許多序列來表示“任意一個字符”、“一個單詞”、“一個可選的字符”等。 一個系統(tǒng)。在搜索操作中,它把子字符串和中間結果的
47、各個部分組合起來。 使用正則表達式,可以對字符串執(zhí)行許多復雜而高級的操作,例如: 區(qū)分(可以是標記或刪除)字符串中所有重復的單詞,例如,把The computer books books轉換為The computer books。 把所有單詞都轉換為標題格式,例如把this is a Title轉換為This Is A Title。 把長于3個字符的所有單詞都轉換為標題格式,例如把this is a Title轉換為This is a Title。 確保句子有正確的大寫形式。 區(qū)分URI的各個元素(例如,提取出協(xié)議、計算機名、文件名等)。當然,這些都是可以在C#中用System.String
48、和 System.Text.StringBuilder執(zhí)行的任務。但是,在一些情況下,還需要編寫相當多的C#代碼。如果使用正則表達式,這些代碼一般可以壓縮為幾行代碼。實際上,是實例化了一個對象System.Text.RegularExpressions.RegEx(甚至更簡單:調用靜態(tài)的RegEx()方法),給它傳送要處理的字符串和一個正則表達式(這是一個字符串,包含用正則表達式語言編寫的指令),就可以了。正則表達式字符串初看起來像是一般的字符串,但其中包含了轉義序列和有特定含義的其他字符。例如,序列b表示一個字的開頭和結尾(字的邊界),如果要表示正在查找以字符th開頭的字,就可以編寫正則表達
49、式bth(即序列字邊界是 t h)。如果要搜索所有以th結尾的字,就可以編寫thb(序列t h字邊界)。但是,正則表達式要比這復雜得多,例如,可以在搜索操作中找到存儲部分文本的工具性程序。本節(jié)僅介紹正則表達式的功能。假定應用程序需要把US電話號碼轉換為國際格式。在美國,電話號碼的格式為314-123-1234,常常寫作(314) 123-1234。在把這個國家格式轉換為國際格式時,必須在電話號碼的前面加上+1(美國的國家代碼),并給區(qū)域代碼加上括號:+1(314) 123-1234。在查找和替換時,這并不復雜,但如果要使用字符串類完成這個轉換,就需要編寫一些代碼(這表示,必須使用System.
50、String上的方法來編寫代碼),而正則表達式語言可以構造一個短的字符串來表達上述含義。所以,本節(jié)只有一個非常簡單的示例,我們只考慮如何查找字符串中的某些子字符串,無須考慮如何修改它們。8.2.2 RegularExpressionsPlayaround示例下面將開發(fā)一個小示例,執(zhí)行并顯示一些搜索的結果,說明正則表達式的一些特性,以及如何在C#中使用.NET正則表達式引擎。這個示例文檔中使用的文本是引自另一本有關XML的Wrox Press書(ASP.NET 1.1高級編程,清華大學出版社翻譯出版):string Text = "This comprehensive compendi
51、um provides a broad and thorough investigation of allaspects of programming with ASP.NET. Entirely revised and updated for the 1.1 Release of .NET, this book will give you the information you need to master ASP.NETand build a dynamic, successful, enterprise Web application."注意:不考慮換行,則上面的表達式是合法的
52、C#代碼 說明了使用字符串時應在前面加上符號。我們把這個文本稱為輸入字符串。為了說明正則表達式.NET類,我們先進行一次純文本的搜索,這次搜索不帶任何轉義序列或正則表達式命令。假定要查找所有的字符串ion,把這個搜索字符串稱為模式。使用正則表達式和上面聲明的變量Text,編寫出下面的代碼:string Pattern = "ion"MatchCollection Matches = Regex.Matches(Text, Pattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);foreach (Mat
53、ch NextMatch in Matches) Console.WriteLine(NextMatch.Index);在這段代碼中,使用了System.Text.RegularExpressions命名空間中Regex類的靜態(tài)方法Matches()。這個方法的參數(shù)是一些輸入文本、一個模式和RegexOptions枚舉中的一組可選標志。在本例中,指定所有的搜索都不應區(qū)分大小寫。另一個標記ExplicitCapture 改變了收集匹配的方式,對于本例,這樣可以使搜索的效率更高,其原因詳見后面的內容(盡管它還有這里沒有介紹的其他用法)。Matches()返回MatchCollections對象的引
54、用。匹配是一個技術術語,表示表達式中模式實例的查找結果,用System.Text.RegularExpressions.Match來代表。因此,我們返回一個包含所有匹配的MatchCollection,每個匹配都用一個Match對象來表示。在上面的代碼中,只是在集合中迭代,使用Match類的Index屬性,返回輸入文本中匹配所在的索引。運行這段代碼,將得到3個匹配。除了一些新的.NET基類外,這些內容都不是新的。但正則表達式的功能主要取決于模式字符串。原因是模式字符串不僅僅包含純文本。如前所述,它還可以包含元字符和轉義序列,其中元字符是給出命令的特定字符,而轉義序列的工作方式與C#的轉義序列相
55、同,它們都是以反斜杠開頭的字符,具有特殊的含義。例如,假定要查找以n開頭的字,就可以使用轉義序列b,它表示一個字的邊界(字的邊界是以某個字母數(shù)字表的字符開頭,或者后面是一個空白字符或標點符號)。可以編寫如下代碼:string Pattern = "bn"MatchCollection Matches = Regex.Matches(Text, Pattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);注意字符串前面的符號。要在運行時把b傳遞給.NET正則表達式引擎,反斜杠不應被C#編譯器解釋為轉義序列。
56、如果要查找以序列ion結尾的字,可以使用下面的代碼:string Pattern = "ionb"如果要查找以字母a開頭,以序列ion結尾的所有字 (在本例中僅有一個匹配application)就必須在上面的代碼中添加一些內容。顯然,我們需要一個以ba開頭,以ionb結尾的模式,但中間的內容怎么辦?需要告訴應用程序在a和ion中間的內容可以是任意長度的任意字符,只要這些字符不是空白即可。實際上,正確的模式如下所示。string Pattern = "baS*ionb"使用正則表達式要習慣的一點是,對像這樣怪異的字符序列見怪不怪。但這個序列的工作是非常邏輯化的。轉義序列S表示任何不是空白的字符。*稱為數(shù)量詞,其含義是前面的字符可以重復任意次,包括0次。序列S*表示任意個不是空白的字符。因此,上面的模式匹配于以a開頭,以ion結尾的任何單詞。表8-4是可以使
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 服裝紡織行業(yè)的顧問工作總結
- 2025年全球及中國無人值守汽車衡亭行業(yè)頭部企業(yè)市場占有率及排名調研報告
- 2025年全球及中國化學鍍鎳 PTFE 涂層行業(yè)頭部企業(yè)市場占有率及排名調研報告
- 2025年全球及中國一體式旋轉變壓器行業(yè)頭部企業(yè)市場占有率及排名調研報告
- 2025-2030全球軟組織水平種植體行業(yè)調研及趨勢分析報告
- 2025-2030全球保險業(yè)的低代碼和無代碼 (LCNC) 平臺行業(yè)調研及趨勢分析報告
- 2025年全球及中國加熱架式食物加熱器行業(yè)頭部企業(yè)市場占有率及排名調研報告
- 2025年全球及中國商用車氣制動防抱死制動系統(tǒng)行業(yè)頭部企業(yè)市場占有率及排名調研報告
- 2025年全球及中國熱水浴缸用換熱器行業(yè)頭部企業(yè)市場占有率及排名調研報告
- 2025年全球及中國變電站智能巡視解決方案行業(yè)頭部企業(yè)市場占有率及排名調研報告
- 給客戶的福利合同(2篇)
- 財務管理專業(yè)《生產(chǎn)實習》教學大綱
- 一年級口算天天練(可直接打印)
- 新急救常用儀器設備操作流程
- 新人教版高中數(shù)學選擇性必修第一冊全套精品課件
- 2023年四川省自貢市中考數(shù)學真題(原卷版)
- SWITCH 勇者斗惡龍11S 金手指 版本:v1.0.3 最大金幣 最大迷你獎章 32倍經(jīng)驗 最大攻擊 所有材料
- 三年級數(shù)學混合運算100題
- 通信工程安全生產(chǎn)手冊
- GB/T 8014-1987鋁及鋁合金陽極氧化陽極氧化膜厚度的定義和有關測量厚度的規(guī)定
- 中醫(yī)醫(yī)院新入職護士培訓大綱
評論
0/150
提交評論