NSCharacterSet ,以及它的可变版本NSMutableCharacterSet,用面向对象的方式来表示一组Unicode字符。它经常与NSString及NSScanner组合起来使用,在不同的字符上做过滤、删除或者分割操作。为了给你提供这些字符是哪些字符的直观印象,请看看NSCharacterSet 提供的类方法:
alphanumericCharacterSet
capitalizedLetterCharacterSet
controlCharacterSet
decimalDigitCharacterSet
decomposableCharacterSet
illegalCharacterSet
letterCharacterSet
lowercaseLetterCharacterSet
newlineCharacterSet
nonBaseCharacterSet
punctuationCharacterSet
symbolCharacterSet
uppercaseLetterCharacterSet
whitespaceAndNewlineCharacterSet
whitespaceCharacterSet
与它的名字所表述的相反,NSCharacterSet 跟 NSSet 一点关系都没有。
去掉空格
NSString -stringByTrimmingCharactersInSet: 是个你需要牢牢记住的方法。它经常会传入 NSCharacterSet +whitespaceCharacterSet 或 +whitespaceAndNewlineCharacterSet 来删除输入字符串的头尾的空白符号。
需要重点注意的是,这个方法 仅仅 去除了 开头 和 结尾 的指定字符集中连续字符。这就是说,如果你想去除单词之间的额外空格,请看下一步。
删除多余的空格
假设你去掉字符串两端的多余空格之后,还想去除单词之间的多余空格,这里有个非常简便的方法:
NSString *string = @"Lorem ipsum dolar sit amet."; string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSArray *components = [string componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; components = [components filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self <> ''"]]; string = [components componentsJoinedByString:@" "];
首先,删除字符串首尾的空格;然后用 NSString -componentsSeparatedByCharactersInSet: 在空格处将字符串分割成一个 NSArray;再用一个 NSPredicate 去除空串;最后,用 NSArray -componentsJoinedByString: 用单个空格符将数组重新拼成字符串。注意:这种方法仅适用于英语这种用空格分割的语言。
字符串分词
不要用 NSCharacterSet 来分词。 用 CFStringTokenizer 来替代它。 你用 componentsSeparatedByCharactersInSet: 来清理用户输入是可以谅解的,但是用它来做更复杂的事情,你将陷入痛苦的深渊。
为什么?请记住,语言并不是都用空格作为词的分界。虽然实际上以空格分界的语言使用非常广泛。但哪怕只算上中国和日本就已经有十多亿人,占了世界人口总量的 16%。
……即使是用空格分隔的语言,分词也有一些模棱两可的边界条件,特别是复合词汇和标点符号。
以上只为说明:如果你想将字符串分成有意义的单词,那么请用 CFStringTokenizer (或者 enumerateSubstringsInRange:options:usingBlock:)吧。
从字符串解析数据
NSScanner 是个用以解析任意或半结构化的字符串的数据的类。当你为一个字符串创建一个扫描器时,你可以指定忽略哪些字符,这样可以避免那些字符以各种各样的方式被包含到解析出来的结果中。
例如,你想从这样一个字符串中解析出开门时间:
Mon-Thurs: 8:00 - 18:00 Fri: 7:00 - 17:00 Sat-Sun: 10:00 - 15:00
你会 enumerateLinesUsingBlock: 并像这样用一个 NSScanner 来解析:
NSMutableCharacterSet *skippedCharacters = [NSMutableCharacterSet punctuationCharacterSet]; [skippedCharacters formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
[hours enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { NSScanner *scanner = [NSScanner scannerWithString:line]; [scanner setCharactersToBeSkipped:skippedCharacters];
NSString *startDay, *endDay; NSUInteger startHour, startMinute, endHour, endMinute;
[scanner scanCharactersFromSet:[NSCharacterSet letterCharacterSet] intoString:&startDay]; [scanner scanCharactersFromSet:[NSCharacterSet letterCharacterSet] intoString:&endDay];
[scanner scanInteger:&startHour]; [scanner scanInteger:&startMinute]; [scanner scanInteger:&endHour]; [scanner scanInteger:&endMinute]; }];
我们首先从空格字符集和标点符号字符集的并集构造了一个 NSMutableCharacterSet。告诉 NSScanner 忽略这些字符以极大地减少解析这些字符的必要逻辑。
scanCharactersFromSet: 传入字母字符集得到每项中一星期内的开始和结束(可选)的天数。scanInteger 类似地,得到下一个连续的整型值。
NSCharacterSet 和 NSScanner 让你可以快速而充满自信地编码。这两者真是完美组合。