NSCharacterSet 简单用法

NSCharacterSet其实是许多字符或者数字或者符号的组合,在网络处理的时候会用到

NSMutableCharacterSet *base = [NSMutableCharacterSet lowercaseLetterCharacterSet]; //字母

NSCharacterSet *decimalDigit = [NSCharacterSet decimalDigitCharacterSet];   //十进制数字

[base formUnionWithCharacterSet:decimalDigit];    //字母加十进制

NSString *string = @"ax@d5s#@sfn$5`SF$$%x^(#e{]e";

//用上面的base隔开string然后组成一个数组,然后通过componentsJoinedByString,来连接成一个字符串

NSLog(@"%@",[[string componentsSeparatedByCharactersInSet:base] componentsJoinedByString:@"-"]);

[base invert];  //非 字母加十进制

NSLog(@"%@",[[string componentsSeparatedByCharactersInSet:base] componentsJoinedByString:@"-"]);

答应结果:

 ax@d-s#@sfn$-`SF$$%x^(#e{]e

---------------------------------------------

正如之前提前过的,基础类库(Foundation)拥有最好的、功能也最全的string类的实现。

但是仅当程序员熟练掌握它时,一个string的实现才是真的好。所以本周,我们将浏览一些基础类库的string生态系统中经常用到且用错的重要组成部分:NSCharacterSet


如果你对什么是字符编码搞不清楚的话(即使你有很好的专业知识),那么你应该抓住这次机会反复阅读Joel Spolsky的这篇经典的文章"The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)"。在头脑中保持新鲜感将对你理解我们将要探讨的话题非常有帮助。

NSCharacterSet ,以及它的可变版本NSMutableCharacterSet,用面向对象的方式来表示一组Unicode字符。它经常与NSStringNSScanner组合起来使用,在不同的字符上做过滤、删除或者分割操作。为了给你提供这些字符是哪些字符的直观印象,请看看NSCharacterSet 提供的类方法:

  • alphanumericCharacterSet
  • capitalizedLetterCharacterSet
  • controlCharacterSet
  • decimalDigitCharacterSet
  • decomposableCharacterSet
  • illegalCharacterSet
  • letterCharacterSet
  • lowercaseLetterCharacterSet
  • newlineCharacterSet
  • nonBaseCharacterSet
  • punctuationCharacterSet
  • symbolCharacterSet
  • uppercaseLetterCharacterSet
  • whitespaceAndNewlineCharacterSet
  • whitespaceCharacterSet

与它的名字所表述的相反,NSCharacterSet 跟 NSSet 一点关系都没有

虽然底层实现不太一样,但是 NSCharacterSet 在概念上跟 NSIndexSet 还有点相似的。NSIndexSet之前提到过,表示一个有序的不重复的无符号整数的集合。Unicode字符跟无符号整数类似,大致对应一些拼写表示。所以,一个 NSCharacterSet +lowercaseCharacterSet 字符集与一个包含97到122范围的 NSIndexSet 是等价的。

现在我们对理解 NSCharacterSet 的基本概念已经有了少许自信,让我们来看一些它的模式与反模式吧:

去掉空格

NSString -stringByTrimmingCharactersInSet: 是个你需要牢牢记住的方法。它经常会传入NSCharacterSet +whitespaceCharacterSet 或 +whitespaceAndNewlineCharacterSet 来删除输入字符串的头尾的空白符号。

需要重点注意的是,这个方法 仅仅 去除了 开头 和 结尾 的指定字符集中连续字符。这就是说,如果你想去除单词之间的额外空格,请看下一步。

挤压空格

假设你去掉字符串两端的多余空格之后,还想去除单词之间的多余空格,这里有个非常简便的方法:

Objective-C

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: 用单个空格符将数组重新拼成字符串。注意:这种方法仅适用于英语这种用空格分割的语言。

现在看看反模式吧。请先看看 the answers to this question on StackOverflow

在写这篇文章的时候,排行第二的正确答案有 58 个顶和 2 个踩。排行第一的有 84 个顶和 24 个踩。

如今,排名第一的答案却不是正确答案是不太正常的,但是这个问题已经破了不重复答案数(10个)的记录,同时也破了不重复、完全错误的答案数(9个)的记录。

言归正传,这里有 9 个错误答案:

  • "Use stringByTrimmingCharactersInSet" - 正如你所知道的,它只去掉首尾的空格。
  • "Replace ' ' with ''" - 这个去除了所有的空格,劳而无功。
  • "Use a regular expression" - 有点用,但它没有处理首尾的空格。用正则表达式有点大材小用了。
  • "Use Regexp Lite" - 说真的,正则表达式真心没必要。同时为了这点功能增加第三方库很不值。
  • "Use OgreKit" - 同上,添加了第三方库。
  • "Split the string into components, iterate over them to find components with non-zero length, and then re-combine" - 很接近了,但是componentsSeparatedByCharactersInSet: 已经让遍历变得没必要。
  • "Replace two-space strings with single-space strings in a while loop" - 错误且浪费计算资源。
  • "Manually iterate over each unichar in the string and use NSCharacterSet -characterIsMember:" - 用了一个复杂到让人吃惊的程度的方法,却忘了标准库中已经有方法可以用。
  • "Find and remove all of the tabs" - 有谁提到了制表符了?不过还是谢谢了吧。

我个人并不是想责怪回答问题的人——只是指出完成这个功能有多少种不同的方法,而这些方法有多少是完全错误的。

字符串分词

不要用 NSCharacterSet 来分词。 用 CFStringTokenizer 来替代它。

你用 componentsSeparatedByCharactersInSet: 来清理用户输入是可以谅解的,但是用它来做更复杂的事情,你将陷入痛苦的深渊。

为什么?请记住,语言并不是都用空格作为词的分界。虽然实际上以空格分界的语言使用非常广泛。但哪怕只算上中国和日本就已经有十多亿人,占了世界人口总量的 16%。

……即使是用空格分隔的语言,分词也有一些模棱两可的边界条件,特别是复合词汇和标点符号。

以上只为说明:如果你想将字符串分成有意义的单词,那么请用 CFStringTokenizer (或者enumerateSubstringsInRange:options:usingBlock:)吧。

从字符串解析数据

NSScanner 是个用以解析任意或半结构化的字符串的数据的类。当你为一个字符串创建一个扫描器时,你可以指定忽略哪些字符,这样可以避免那些字符以各种各样的方式被包含到解析出来的结果中。

例如,你想从这样一个字符串中解析出开门时间:

Text

Mon-Thurs:  8:00 - 18:00
Fri: 7:00 - 17:00
Sat-Sun: 10:00 - 15:00

你会 enumerateLinesUsingBlock: 并像这样用一个 NSScanner 来解析:

SwiftObjective-C

let skippedCharacters = NSMutableCharacterSet()
skippedCharacters.formIntersectionWithCharacterSet(NSCharacterSet.punctuationCharacterSet())
skippedCharacters.formIntersectionWithCharacterSet(NSCharacterSet.whitespaceCharacterSet()) string.enumerateLines { (line, _) in
let scanner = NSScanner(string: line)
scanner.charactersToBeSkipped = skippedCharacters var startDay, endDay: NSString?
var startHour: Int = 0
var startMinute: Int = 0
var endHour: Int = 0
var endMinute: Int = 0 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 让你可以快速而充满自信地编码。这两者真是完美组合。


NSCharacterSet 是基础类库中字符串处理系统中的一员,可能是最容易被用错或是误解的一员。在脑中记住这些模式与反模式,你将不仅能做一些很有用的诸如管理空格及从字符串中读信息之类的事情,更重要的是,你将避免误入歧途。

如果“不出错”对一个 NSHipster 来说不是最重要的事情,那我也不想成为正确的了!

Ed. Speaking of (not) being wrong, the original version of this article contained errors in both code samples. These have since been corrected.

NSCharacterSet 简单用法的更多相关文章

  1. CATransition(os开发之画面切换) 的简单用法

    CATransition 的简单用法 //引进CATransition 时要添加包“QuartzCore.framework”,然后引进“#import <QuartzCore/QuartzCo ...

  2. jquery.validate.js 表单验证简单用法

    引入jquery.validate.js插件以及Jquery,在最后加上这个插件的方法名来引用.$('form').validate(); <!DOCTYPE html PUBLIC " ...

  3. [转]Valgrind简单用法

    [转]Valgrind简单用法 http://www.cnblogs.com/sunyubo/archive/2010/05/05/2282170.html Valgrind的主要作者Julian S ...

  4. Oracle的substr函数简单用法

    substr(字符串,截取开始位置,截取长度) //返回截取的字 substr('Hello World',0,1) //返回结果为 'H'  *从字符串第一个字符开始截取长度为1的字符串 subst ...

  5. Ext.Net学习笔记19:Ext.Net FormPanel 简单用法

    Ext.Net学习笔记19:Ext.Net FormPanel 简单用法 FormPanel是一个常用的控件,Ext.Net中的FormPanel控件同样具有非常丰富的功能,在接下来的笔记中我们将一起 ...

  6. TransactionScope简单用法

    记录TransactionScope简单用法,示例如下: void Test() { using (TransactionScope scope = new TransactionScope()) { ...

  7. WPF之Treeview控件简单用法

    TreeView:表示显示在树结构中分层数据具有项目可展开和折叠的控件 TreeView 的内容是可以包含丰富内容的 TreeViewItem 控件,如 Button 和 Image 控件.TreeV ...

  8. listActivity和ExpandableListActivity的简单用法

    http://www.cnblogs.com/limingblogs/archive/2011/10/09/2204866.html 今天自己简单的总结了listActivity和Expandable ...

  9. SQL*Plus break与compute的简单用法

    SQL*Plus break与compute的简单用法在SQL*Plus提示符下输出求和报表,我们可以借助break与compute两个命令来实现.这个两个命令简单易用,可满足日常需求,其实质也相当于 ...

随机推荐

  1. Datasets for Data Mining and Data Science

    https://github.com/mattbane/RecommenderSystem http://grouplens.org/datasets/movielens/ KDDCUP-2012官网 ...

  2. 对 Linux 新手非常有用的 20 个命令

    参考:http://www.oschina.net/translate/useful-linux-commands-for-newbies 英文原文:http://www.tecmint.com/us ...

  3. 【转】 JSONObject使用方法

    随笔- 46  文章- 0  评论- 132 JSONObject简介 本节摘要:之前对JSON做了一次简单的介 绍,并把JSON和XML做了一个简单的比较:那么,我就在想,如果是一个json格式的字 ...

  4. JavaEE填空与判断

    Java EE软件工程师认证考试 试题库- 填空题和选择题   一.     填空题 1. HTML网页文件的标记是__html__,网页文件的主体标记是_body__,标记页面标题的标记是__tit ...

  5. c++ template函数的声明和实现需要在同一个文件中

    新建一个class C;生成2个文件C.h和C.cpp,在C.h中声明一个函数 template<class T> T stringTo(char* str); 直接用VAssistX的R ...

  6. hadoop命令备忘

    hadoop dfsadmin -safemode get 查看namenode是否处于安全模式 hadoop dfsadmin -report 显示文件系统的统计信息,以及所连接的各个datanod ...

  7. Maven类包冲突终极解决方案

    本文转自:http://ian.wang/106.htm 举例A依赖于B及C,而B又依赖于X.Y,而C依赖于X.M,则A除引B及C的依赖包下,还会引入X,Y,M的依赖包(一般情况下了,Maven可通过 ...

  8. Android之自定义ViewGroup

    概述 在写代码之前,我必须得问几个问题: 1.ViewGroup的职责是啥? ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性, ...

  9. iOS及时log日志查看工具 (iConsole)

    github下载地址:https://github.com/nicklockwood/iConsole 偶然看到的一个iOS及时log日志查看工具,通过该工具,我们可以在任何想看日志的时候,通过手势呼 ...

  10. 查询MYSQL和查询HBASE速度比较

    上一篇文章:我要上谷歌 Mysql,关系型数据库: HBase,NoSql数据库. 查询Mysql和查询HBase,到底哪个速度快呢? 与一些真正的大牛讨论时,他们说HBase写入速度,可以达到每秒1 ...