詳解Cocoa字符串
Cocoa字符串是本文要介紹的內(nèi)容,我們首先談了用NSString提供的各個method創(chuàng)建子串的主要步驟,然后還討論如問褂謎廡┳址??N頤墻喲チ死啻氐讓嫦蚨韻蟊喑痰哪諶藎?約耙恍┘虻サ淖址??募蘒/O的操作。另外,還花了很多時間討論比較,搜索和抽取子串的method。
本文我想跟大家討論NSString的文件路徑工具,以及NSString的子類:NSMutableString,它的內(nèi)容可以在創(chuàng)建以后進行更改—這一點單純靠NSString無法實現(xiàn)。***,我們會以一些雜項字符串method。好,現(xiàn)在讓我們開始。
處理文件路徑字符串
在前面的章節(jié)中我演示了我們?nèi)绾伟炎址畬懙轿谋疚募校约叭绾螐奈谋疚募腥绾蝿?chuàng)建新字符串。在上面的情形中,我們用字符串來表達文件的位置(路徑)。這會在我們處理文件是經(jīng)常碰到,也就是說,存儲文件路徑的NSString字符串對象。
Cocoa中文件路徑的字符串表示是標準的,NSString也提供了一系列的method供我們處理文件路徑字符串。這些method幫助我們把相對路徑替換為絕對路徑,解析符號鏈接,抽取路徑成分到新的字符串中,以及處理文件擴展名。
現(xiàn)在我們都知道Mac OS X是建筑在Unix之上的(我很希望蘋果電腦能夠通過這一個步驟獲得發(fā)展),因此,目錄和文件都是按照Unix的方式進行組織和操作的。有幾點與一般的Macintosh不同方式是我們需要了解的(我相信多數(shù)人都知道這些,但包括一些基礎(chǔ)知識總不是一件壞事,希望大家能夠忍耐這一點)。
在Unix中,用戶的主目錄縮寫為波浪號(“~”)。這是在文件系統(tǒng)中移動的很有用的快捷方式。例如,我在我的iBook上的主目錄的擴展形式為/Users/mike/,簡寫形式為~。但是,路徑字符串中的波浪號并不會被認為事合法的路徑,所以我們要使用-stringByExpandingTildeInPath這個method來擴展路徑。下面是例子:
- NSString *shortPath = @"~/textFile.txt";
- NSString *absolutePath = [shortPath stringByExpandTildeInPath];
- stringByExpandingTildeInPath這個method通過把波浪號替換為當(dāng)前用戶的主目錄,來把textFile.txt轉(zhuǎn)換為擴展的絕對路徑?,F(xiàn)在新的路徑是/User/mike/textFile.txt。我們也可以反過來做,把用戶的主目錄路徑替換為波浪號。我們使用的method是:-stringByAbbreviatingWithTildeInPath:
- NSString *path = [absolutepath stringByAbbreviatingWithTildeInPath];
它會把path變量設(shè)置為~/textFile.txt。我們注意到在所有的這些method中(以前我們上次談到的)***個單詞都是“string”,它的意思是這些以string開頭的消息返回的都是一個字符串。這種語法在Cocoa中很常見,我們會在數(shù)組,數(shù)字,字典等中看到它。Cocoa的method命名盡量能做到不含混(這的確會使輸入的字母增加,但我覺得可讀,不含混的代碼是值得的)。
文件擴展名在Unix中很流行(很多Mac用戶不屑于這一點)。文件擴展名是附加在文件名之后的一些字符,兩者之間用句點分開(在Cocoa中,句點本身不算擴展名的部分)。我們可以通過調(diào)用- pathExtension來產(chǎn)生一個包含擴展名的新字符串。它返回一個NSString對象,包含文件擴展名,不包括句點。
- NSString *path = @"~/textFile.txt";
- NSString *pathExtension = [path pathExtension];
pathExtension這個字符串的值將是“txt”。句點將被去掉了。如果沒有句點指明擴展名,將返回一個空串。如果文件不存在,也將返回空串。
顯然,還有一個method來做相反的事情,也就是,給文件名添上擴展名。這個method是:-stringByAppendingPathExtension:。如果我們有一個路徑字符串是:/Users/mike/textFile,我們可以用以下的辦法給它添上擴展名:
- NSString *path = @"/User/mike/textFile";
- path = [path stringByAppendingPathExtension: @"txt"];
這樣,path變量的值為/Users/mike/textFile.txt。注意,我們在這個例子中吧返回的新字符串重新存在原來的變量中。
如果我們需要去掉擴展名,而只留下路徑和文件名,我們可以使用method:-stringByDeletingPathExtension。我們用回我們原來的路徑/Users/mike/textFile.txt:
- path = [path stringByDeletingPathExtension];
現(xiàn)在path變量將為/Users/mike/textFile。這個method返回原始的字符串,而去掉了擴展名(包括連接擴展名的句點)。
NSString中另一套有用的路徑操作工具是使我們操作路徑的各個部分:如各個目錄名,文件名等。首先是-pathComponents??雌饋砗芎唵?,它做的事情是把一個路徑字符串按照斜線分隔拆成幾個子串,并把它們放到一個NSArray對象中。我們現(xiàn)在還沒有談到NSArray,但它其實只不過是Cocoa風(fēng)格的標準數(shù)組。所以,如果我們有以下的路徑:
- NSString *thisColumn = @"/Users/mike/Documents/Cocoa_Column/Column8.doc"
(我承認,我相當(dāng)喜歡Word這個程序。) -pathComponents將把它拆開,并放到一個數(shù)組中,就象這樣:
- NSArray *theComponents = [thisColumn pathComponents];
結(jié)果的數(shù)組大概是這樣的,如圖:
它使得我們可以完全控制訪問任意層次的目錄和文件變得很容易。如果我們得需求比較簡單,我們可以使用一些控制***一個單元的method,通常這已經(jīng)足夠了。它們是-lastPathComponent,-stringByAppendingPathComponent:,和-stringByDeletingLastPathComponent。它們的作用和它們的名字是一樣的。如果是同樣的上邊的路徑,
NSString *thisColumn = @"/Users/mike/Documents/Cocoa_Column/Column8.doc"
然后我們執(zhí)行以下的代碼:
- NSString *lastComponent = [thisColumn lastPathComponent];
- NSString *pathLessFilename = [thisColumn stringByDeletingLastPathComponent];
- NSString *originalPath = [pathLessFilename stringByAppendingPathComponent: lastComponent];
***,originalPath和thisColumn是相等的。原因是,***行我們創(chuàng)建了一個新的字符串,它的值是lastPathComponent(這些method的命名是不是很好?)返回的thisColumn的***一個路徑單元:“Column8.doc”。第二行我們創(chuàng)建了另外一個字符串,它是Column8.doc所在的目錄。***一行,我們又把這兩部分合成為原來的路徑。
現(xiàn)在,你已經(jīng)看到了一些處理路徑的method。你可以在NSString的類使用指南中看到全部的敘述。自然,使用指南的描述會比我們這里更加詳細些。
下面是可變字符串!
可變字符串
前面我們討論NSString的時候,我提過基本的Cocoa字符串是Unicode字符的不可變數(shù)組。這意味著當(dāng)我們創(chuàng)建一個字符串后,我們就一直使用它,我們沒有辦法通過NSString來改變它。NSMutableString則是我們的解決方案。NSMutableString是NSString的一個子類,它可以使我們做我們以前做不到的事情—我們現(xiàn)在可以創(chuàng)建能夠改變其內(nèi)容的字符串了。
因為NSMutableString是NSString的子類,所以我們前面學(xué)過的關(guān)于字符串操作同樣適用于可變字符串。在這部分中,我想帶你涉足NSMutableString對NSString所添加的method,以只是對可變字符串的編輯(對NSString的實例,我將稱為字符串;而對NSMutableString,則稱為可變字符串)。
我們有兩個method可以在現(xiàn)有的可變字符串的尾部添加內(nèi)容:他們是:-appendString:和-appendFormat:,他們的使用方法是:
- NSMutableString *aMutableString = [[NSMutableString alloc] initWithString: @"Hello"];
- [aMutableString appendString: @", World!"];
發(fā)送給aMutableString的appendString消息告訴它把消息的參數(shù)添加到末尾,所以aMutableString的結(jié)果值是“Hello, World!”。這里有兩件事情是需要注意的。首先,我們不能直接使用@"..."來構(gòu)造可變字符串。這個算符產(chǎn)生的字符串是被編譯到執(zhí)行代碼中并總是存在的。很明顯,我們不能改變一個預(yù)編譯字符串,所以我們要想處理其他對象一樣用alloc和init這兩個method來創(chuàng)建新的NSMutableString對象。我們也可以用NSString中聲明的所有init...系列的method,因為它是NSMutableString的父類。
另外,我們也注意到NSMutableString的內(nèi)容編輯類的method都不返回值,他們的返回類型是void。這些method實際上都是直接修改接收者字符串的值,而不是象我們在NSString中那樣返回一個修改后的新拷貝。
我們也可以用-appendFormat:在現(xiàn)有的字符串后面添加格式化字符串。這和前面的method是類似的,除了我們可以用上一章學(xué)習(xí)的辦法來格式化字符串。
-deleteCharactersInRange這個method的唯一的參數(shù)是一個范圍(NSRange數(shù)據(jù)類型),它把接收者字符串中在這個范圍的字符清除掉。要形成一個范圍,基本框架提供了一個函數(shù)(不是類的method,而是標準的C函數(shù)):NSMakeRange(unsigned int location, unsigned int length),它的參數(shù)是形成范圍的兩個變量,返回一個NSRange變量。***個參數(shù)是范圍的***個字符的索引值(想象一下數(shù)組—從0開始計數(shù)),第二個參數(shù)是包括***個字符在內(nèi)范圍的長度。我們可以把我們前面例子中添加的字符串清除掉,并得到原來的字符串,“Hello”:
- NSRange aRange = NSMakeRange(5,8);
- [aMutableString deleteCharactersInRange: aRange];
下一個NSMutableString的method是-insertString: atIndex: ,它的作用是把一個參數(shù)給定的字符串插入到第二個參數(shù)指明的位置中,這個位置是以索引編號表示的。接收者字符串插入位置及其后面的字符串會被向后移動以給插入的字符串留出空間。method的使用方法如下:
- NSMutableString *aMutableString = [[NSMutableString alloc] initWithString: @"Hello, World!";
- [aMutableString insertString: @" (not goodbye)" atIndex: 5];
上面的代碼會把aMutableString的值改為“Hello (not goodbye), World!”。你將注意到我們插入的單詞的***個字符是一個空格。記數(shù)組的索引號是從0開始的,所以,aMutableString的***個字符“H”在0的位置。
如果我們想把一個字符串的值從一個完全改變成另外一個,我們可以使用-setString:這個method。所以,我們可以把上面的結(jié)果字符串a(chǎn)MutableString改成任意值:
- [aMutableString setString: @"Whatever."];
現(xiàn)在aMutableString的值改為“whatever”。從這個method我們可以聯(lián)想到我們在NSControl中的set...系列method。
我們可變字符串工具箱里面的***一個method是:-replaceCharactersInRange: withString:,它完成的事情和它的名字一樣(替換范圍內(nèi)的字符串)。***個參數(shù)是你想替換的范圍,第二個參數(shù)是要替換進去的字符串。這只是一個很簡單的替換操作。我們看看代碼的寫法:
- NSMutableString *aString = [[NSMutableString alloc] initWithString: @"Hello, World!"];
- [aString replaceCharactersInRange: NSMakeRange(7,5) withString: @"Universe"];
現(xiàn)在,我們原來的字符串“Hello, World”被改變?yōu)?ldquo;Hello, Universe!”。
雜項
在結(jié)束這章以前,我還想講一下NSString中改變字符大小寫和從字符串中獲取數(shù)值的方法。
在色彩表程序的章節(jié),我們談到向控件對象發(fā)送以下消息:intValue,doubleValue和floatValue來獲得數(shù)值。對字符串也是這樣的。也就是說,NSString也象我們以前談的那樣響應(yīng)這些消息(多態(tài)性)。但是,要求是這個字符串必須是數(shù)值。我們不能用這些method從字符串中挑出數(shù)字來。我們可以從字符串中找到一個數(shù)字,然后用這個method返回C類型的數(shù)值。假設(shè)我們有一個包含一些文本的字符串,在字符串的***面是一個數(shù)字。我們可以用下面的辦法把它找出來:
- NSString *textAndNumbers = @"Number of eggs in a dozen= 12";
- NSString *numberPart = [textAndNumbers substringFromIndex: 27];
- int numberInADozen = [numberPart intValue];
我承認,上面的例子其實不是很實際,但我希望能夠給你一些啟發(fā)。需要記住的是,你要根據(jù)字符串中數(shù)據(jù)的類型和目標數(shù)據(jù)類型,選擇合適的...Value系列的method。
***一個我想告訴你的關(guān)于NSString的小玩意是讓我們改變字符串里面的大小寫:-capitalizedString,lowercaseString和uppercaseString。lowercaseString返回一個全是小寫字母的字符串,-uppercaseString差不多,但返回的是全是大寫。-capitalizedString有些古怪,返回的字符串的每個單詞的***個字母變成大寫。下面是例子:
- NSString *string = @"tHe uniVERSity of TEXAS";
- NSString *lcstring = [string lowercaseString];
- NSString *ucstring = [string uppercaseString];
- NSString *capstring = [string capitalizedString];
***三行分別把字符串轉(zhuǎn)換為“the university of texas”,“THE UNIVERSITY OF TEXAS”和“The University Of Texas”。
在本章中我們初步涉及了Cocoa字符串處理方面的功能。我曾經(jīng)提過你應(yīng)該看一下NSString的類使用指南(希望你已經(jīng)將基礎(chǔ)類和應(yīng)用類的指南頁面添加到你的收藏夾中了)來獲得這里沒有討論的其他method的詳細信息。我這里說的都是處理字符串的基本方法,以給你信心和大致的原則以做進一步研究NSString的高級部分。
小結(jié):關(guān)于詳解Cocoa字符串的內(nèi)容介紹完了,希望本文對你有所幫助!