Cocoa字符串是本文要介绍的内容,我们首先谈了用NSString提供的各个method创建子串的主要步骤,然后还讨论如问褂谜庑┳址??N颐墙哟チ死啻氐让嫦蚨韵蟊喑痰哪谌荩?约耙恍┘虻サ淖址??募蘒/O的操作。另外,还花了很多时间讨论比较,搜索和抽取子串的method。
本文我想跟大家讨论NSString的文件路径工具,以及NSString的子类:NSMutableString,它的内容可以在创建以后进行更改—这一点单纯靠NSString无法实现。***,我们会以一些杂项字符串method。好,现在让我们开始。
处理文件路径字符串
在前面的章节中我演示了我们如何把字符串写到文本文件中,以及如何从文本文件中如何创建新字符串。在上面的情形中,我们用字符串来表达文件的位置(路径)。这会在我们处理文件是经常碰到,也就是说,存储文件路径的NSString字符串对象。
Cocoa中文件路径的字符串表示是标准的,NSString也提供了一系列的method供我们处理文件路径字符串。这些method帮助我们把相对路径替换为绝对路径,解析符号链接,抽取路径成分到新的字符串中,以及处理文件扩展名。
现在我们都知道Mac OS X是建筑在Unix之上的(我很希望苹果电脑能够通过这一个步骤获得发展),因此,目录和文件都是按照Unix的方式进行组织和操作的。有几点与一般的Macintosh不同方式是我们需要了解的(我相信多数人都知道这些,但包括一些基础知识总不是一件坏事,希望大家能够忍耐这一点)。
在Unix中,用户的主目录缩写为波浪号(“~”)。这是在文件系统中移动的很有用的快捷方式。例如,我在我的iBook上的主目录的扩展形式为/Users/mike/,简写形式为~。但是,路径字符串中的波浪号并不会被认为事合法的路径,所以我们要使用-stringByExpandingTildeInPath这个method来扩展路径。下面是例子:
- NSString *shortPath = @"~/textFile.txt";
- NSString *absolutePath = [shortPath stringByExpandTildeInPath];
- stringByExpandingTildeInPath这个method通过把波浪号替换为当前用户的主目录,来把textFile.txt转换为扩展的绝对路径。现在新的路径是/User/mike/textFile.txt。我们也可以反过来做,把用户的主目录路径替换为波浪号。我们使用的method是:-stringByAbbreviatingWithTildeInPath:
- NSString *path = [absolutepath stringByAbbreviatingWithTildeInPath];
它会把path变量设置为~/textFile.txt。我们注意到在所有的这些method中(以前我们上次谈到的)***个单词都是“string”,它的意思是这些以string开头的消息返回的都是一个字符串。这种语法在Cocoa中很常见,我们会在数组,数字,字典等中看到它。Cocoa的method命名尽量能做到不含混(这的确会使输入的字母增加,但我觉得可读,不含混的代码是值得的)。
文件扩展名在Unix中很流行(很多Mac用户不屑于这一点)。文件扩展名是附加在文件名之后的一些字符,两者之间用句点分开(在Cocoa中,句点本身不算扩展名的部分)。我们可以通过调用- pathExtension来产生一个包含扩展名的新字符串。它返回一个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];
现在path变量将为/Users/mike/textFile。这个method返回原始的字符串,而去掉了扩展名(包括连接扩展名的句点)。
NSString中另一套有用的路径操作工具是使我们操作路径的各个部分:如各个目录名,文件名等。首先是-pathComponents。看起来很简单,它做的事情是把一个路径字符串按照斜线分隔拆成几个子串,并把它们放到一个NSArray对象中。我们现在还没有谈到NSArray,但它其实只不过是Cocoa风格的标准数组。所以,如果我们有以下的路径:
- NSString *thisColumn = @"/Users/mike/Documents/Cocoa_Column/Column8.doc"
(我承认,我相当喜欢Word这个程序。) -pathComponents将把它拆开,并放到一个数组中,就象这样:
- NSArray *theComponents = [thisColumn pathComponents];
结果的数组大概是这样的,如图:
它使得我们可以完全控制访问任意层次的目录和文件变得很容易。如果我们得需求比较简单,我们可以使用一些控制***一个单元的method,通常这已经足够了。它们是-lastPathComponent,-stringByAppendingPathComponent:,和-stringByDeletingLastPathComponent。它们的作用和它们的名字是一样的。如果是同样的上边的路径,
NSString *thisColumn = @"/Users/mike/Documents/Cocoa_Column/Column8.doc"
然后我们执行以下的代码:
- NSString *lastComponent = [thisColumn lastPathComponent];
- NSString *pathLessFilename = [thisColumn stringByDeletingLastPathComponent];
- NSString *originalPath = [pathLessFilename stringByAppendingPathComponent: lastComponent];
***,originalPath和thisColumn是相等的。原因是,***行我们创建了一个新的字符串,它的值是lastPathComponent(这些method的命名是不是很好?)返回的thisColumn的***一个路径单元:“Column8.doc”。第二行我们创建了另外一个字符串,它是Column8.doc所在的目录。***一行,我们又把这两部分合成为原来的路径。
现在,你已经看到了一些处理路径的method。你可以在NSString的类使用指南中看到全部的叙述。自然,使用指南的描述会比我们这里更加详细些。
下面是可变字符串!
可变字符串
前面我们讨论NSString的时候,我提过基本的Cocoa字符串是Unicode字符的不可变数组。这意味着当我们创建一个字符串后,我们就一直使用它,我们没有办法通过NSString来改变它。NSMutableString则是我们的解决方案。NSMutableString是NSString的一个子类,它可以使我们做我们以前做不到的事情—我们现在可以创建能够改变其内容的字符串了。
因为NSMutableString是NSString的子类,所以我们前面学过的关于字符串操作同样适用于可变字符串。在这部分中,我想带你涉足NSMutableString对NSString所添加的method,以只是对可变字符串的编辑(对NSString的实例,我将称为字符串;而对NSMutableString,则称为可变字符串)。
我们有两个method可以在现有的可变字符串的尾部添加内容:他们是:-appendString:和-appendFormat:,他们的使用方法是:
- NSMutableString *aMutableString = [[NSMutableString alloc] initWithString: @"Hello"];
- [aMutableString appendString: @", World!"];
发送给aMutableString的appendString消息告诉它把消息的参数添加到末尾,所以aMutableString的结果值是“Hello, World!”。这里有两件事情是需要注意的。首先,我们不能直接使用@"..."来构造可变字符串。这个算符产生的字符串是被编译到执行代码中并总是存在的。很明显,我们不能改变一个预编译字符串,所以我们要想处理其他对象一样用alloc和init这两个method来创建新的NSMutableString对象。我们也可以用NSString中声明的所有init...系列的method,因为它是NSMutableString的父类。
另外,我们也注意到NSMutableString的内容编辑类的method都不返回值,他们的返回类型是void。这些method实际上都是直接修改接收者字符串的值,而不是象我们在NSString中那样返回一个修改后的新拷贝。
我们也可以用-appendFormat:在现有的字符串后面添加格式化字符串。这和前面的method是类似的,除了我们可以用上一章学习的办法来格式化字符串。
-deleteCharactersInRange这个method的唯一的参数是一个范围(NSRange数据类型),它把接收者字符串中在这个范围的字符清除掉。要形成一个范围,基本框架提供了一个函数(不是类的method,而是标准的C函数):NSMakeRange(unsigned int location, unsigned int length),它的参数是形成范围的两个变量,返回一个NSRange变量。***个参数是范围的***个字符的索引值(想象一下数组—从0开始计数),第二个参数是包括***个字符在内范围的长度。我们可以把我们前面例子中添加的字符串清除掉,并得到原来的字符串,“Hello”:
- NSRange aRange = NSMakeRange(5,8);
- [aMutableString deleteCharactersInRange: aRange];
下一个NSMutableString的method是-insertString: atIndex: ,它的作用是把一个参数给定的字符串插入到第二个参数指明的位置中,这个位置是以索引编号表示的。接收者字符串插入位置及其后面的字符串会被向后移动以给插入的字符串留出空间。method的使用方法如下:
- NSMutableString *aMutableString = [[NSMutableString alloc] initWithString: @"Hello, World!";
- [aMutableString insertString: @" (not goodbye)" atIndex: 5];
上面的代码会把aMutableString的值改为“Hello (not goodbye), World!”。你将注意到我们插入的单词的***个字符是一个空格。记数组的索引号是从0开始的,所以,aMutableString的***个字符“H”在0的位置。
如果我们想把一个字符串的值从一个完全改变成另外一个,我们可以使用-setString:这个method。所以,我们可以把上面的结果字符串aMutableString改成任意值:
- [aMutableString setString: @"Whatever."];
现在aMutableString的值改为“whatever”。从这个method我们可以联想到我们在NSControl中的set...系列method。
我们可变字符串工具箱里面的***一个method是:-replaceCharactersInRange: withString:,它完成的事情和它的名字一样(替换范围内的字符串)。***个参数是你想替换的范围,第二个参数是要替换进去的字符串。这只是一个很简单的替换操作。我们看看代码的写法:
- NSMutableString *aString = [[NSMutableString alloc] initWithString: @"Hello, World!"];
- [aString replaceCharactersInRange: NSMakeRange(7,5) withString: @"Universe"];
现在,我们原来的字符串“Hello, World”被改变为“Hello, Universe!”。
杂项
在结束这章以前,我还想讲一下NSString中改变字符大小写和从字符串中获取数值的方法。
在色彩表程序的章节,我们谈到向控件对象发送以下消息:intValue,doubleValue和floatValue来获得数值。对字符串也是这样的。也就是说,NSString也象我们以前谈的那样响应这些消息(多态性)。但是,要求是这个字符串必须是数值。我们不能用这些method从字符串中挑出数字来。我们可以从字符串中找到一个数字,然后用这个method返回C类型的数值。假设我们有一个包含一些文本的字符串,在字符串的***面是一个数字。我们可以用下面的办法把它找出来:
- NSString *textAndNumbers = @"Number of eggs in a dozen= 12";
- NSString *numberPart = [textAndNumbers substringFromIndex: 27];
- int numberInADozen = [numberPart intValue];
我承认,上面的例子其实不是很实际,但我希望能够给你一些启发。需要记住的是,你要根据字符串中数据的类型和目标数据类型,选择合适的...Value系列的method。
***一个我想告诉你的关于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];
***三行分别把字符串转换为“the university of texas”,“THE UNIVERSITY OF TEXAS”和“The University Of Texas”。
在本章中我们初步涉及了Cocoa字符串处理方面的功能。我曾经提过你应该看一下NSString的类使用指南(希望你已经将基础类和应用类的指南页面添加到你的收藏夹中了)来获得这里没有讨论的其他method的详细信息。我这里说的都是处理字符串的基本方法,以给你信心和大致的原则以做进一步研究NSString的高级部分。
小结:关于详解Cocoa字符串的内容介绍完了,希望本文对你有所帮助!