Swift3.0 中 Strings/Characters 闲聊

前言
本篇文章主要浅析字符串\字符在 Swift 和 Objective-C 之间的区别及其简单用法。如有不妥的地方还望大家及时帮忙纠正。
字符串判空
在 swift 语言中空字符串初始化方式常用的有两种:
// 方式一:
let testEmptyString0 = ""
// 方式二:
let testEmptyString1 = String()
在开发过程中,我们应该如何用正确的方式来对字符串进行判空处理呢?
// 方式一:这种方式其实就是判断 characters.count 是否为0
if testEmptyString0.isEmpty {
// empty
}
// 方式二:
if testEmptyString0.characters.count {
// empty
}
// 方式三:
if (testEmptyString0 as NSString).length {
// empty
}
字符串长度计算
Objective-C
首先我们来回忆一下,在 Objective-C 中字符串是怎么计算长度的?我想大家都应该知道。来看看苹果是怎么说的:
A string object is implemented as an array of Unicode characters (in other words, a text string). An immutable string is a text string that is defined when it is created and subsequently cannot be changed. To create and manage an immutable string, use the NSString class. To construct and manage a string that can be changed after it has been created, use NSMutableString.
A string object presents itself as an array of Unicode characters. You can determine how many characters it contains with the length method and can retrieve a specific character with the characterAtIndex: method.
看完这段话,想必大家都明白 NSString 是怎么实现的,以及如何获取其长度。通过 length 方法即可,那么 length 方法是如何实现的呢?苹果官方是这样说的:length 方法利用的是 UTF-16 表示的十六位编码单元数字为单位进行计算的(The number of UTF-16 code units in the receiver.)。UTF-16是什么?(感兴趣的童鞋可以看一下我之前写的一篇文章,字符编码(一)),此处不再详述。
Swift 3.0
Unicode 标量表示
在 Swift 中,字符和字符串都是基于 Unicode 标量建立的,采用21位二进制进行编码,共17个平面(除了基本多文种平面中的 UTF-16 代理对码位外,即U+D800至U+DFFF的编码空间),也就是说编码范围是U+0000-U+D7FFF 或者 U+E000-U+10FFFF。
A Unicode scalar is any Unicode code point in the range U+0000 to U+D7FF inclusive or U+E000 to U+10FFFF inclusive. Unicode scalars do not include the Unicode surrogate pair code points, which are the code points in the range U+D800 to U+DFFF inclusive.”
因此在 Swift 中,我们可直接采用 Unicode 标量的形式来表示字符或字符串,如:
let tingC = "\u{542C}" // 听
let xinC = "\u{5FC3}" // 心
可扩展的字形群集(簇)
在 Swift 中,每一个 Character 类型实例都代表单个可扩展的字形群集——即由一个或多个 Unicode 标量的序列组成的一个可读字符。
汉字 “听” 拼音为 tīng,以字母 ī 为例,用两种方式表示。第一种,可以直接用单个 Unicode 标量 ī (LATIN SMALL LETTER I WITH MACRON) 来表示,即 U+012B,该字形群集中包含一个 Unicode 标量。第二种,可以采用两个 Unicode 标量来表示,一个拉丁字母 i (LATIN SMALL LETTER I) 加上一个音调符(元音,COMBINING MACRON ACCENT)的标量,即 U+0069 U+0304,这样,当字母 i 被 Unicode 文字渲染系统时就会转换成 ī,该字形群集中包含两个 Unicode 标量。
let tingO = "t" + "\u{0069}" + "ng" // Prints "ting "
let tingPS = "t" + "\u{0069}" + "\u{0304}" + "ng" // Prints "tīng"
let tingPD = "t" + "\u{012B}" + "ng" // Prints "tīng"
这两种情况中,字母 ī 即代表了 Swift 中单个 Character 类型实例,也代表了一个可扩展的字形群集。想了解更多关于可扩展的字形群集,可参考此链接。
字符串长度
我们已经简单了解了可扩展的字形群集,现在我们再来看看 Swift 字符串中一些有意思的事。
Swift 中 String 类型,说白了就是 Character 类型实例的集合,在开发过程中,我们一般采用两种方式来求字符串的长度,第一种是转成 Objective-C 中的 NSString 类型,通过 length 方法来获取其长度,第二种是通过字符串属性 characters.count 的方式获得。本小节主要讨论第二种,本文会在结尾针对这两种方式进行比较。
在 Swift 中,细心的同学或许已经发现 tingPD 与 tingPS 字符串的字符数量是一样的:
print("tingPD-Count:\(tingPD.characters.count), tingPS-Count:\(tingPS.characters.count)")
// Prints "tingPD-Count:4, tingPS-Count:4"
下面我们来解决此疑惑,笔者已在前文说过,Swift 中 String\Character 都是基于 Unicode 标量建立的,且 String 是 Character 的集合(即包含关系),而 String 属性 characters.count 其实就是计算 Character 的数量,那么 character 是怎么定义的呢,或者说什么才算是一个 character?此时又引出了一个概念——字形群集界限(Grapheme Cluster Boundaries),而”什么才算是一个 character?“这个问题就是字形群集界限给出的答案,想深入了解的同学请看:传送门。从用户感观(user-perceived)角度讲,不管是字符 ī(U+012B) 或者是 i(U+0069) 再加上一个音调符(U+0304),这两种表示最终的结果都是组成一个相同的可读的字符,因此 tingPD 与 tingPS 字符串中的字符数量是一样的。
通过上文的简单解释,可以得出两个结论:
一个字符串拼接一个字符时,不一定会更改字符串的数量,即 characters.count 的值。
在没有获取到字形群集界限的时候,无法计算出该字符串的字符数量,因此必须遍历字符串中全部的 Unicode 标量以获取字形群集界限,进而确定字符串的字符数量。
下面在看一个例子,相信大家都已明白输出结果的原因:
var iWord = "i"
print("iword-Count: \(iWord.characters.count)")
// Prints "iword-Count: 1"
iWord += "\u{0304}" // ī
print("iword-Count: \(iWord.characters.count)")
// Prints "iword-Count: 1"
.length 与 .characters.count 的区别
首先 .length 是 Objective-C 中字符串长度计算方法,而 .characters.count 可以说是 Swift 中字符串长度计算方法,由于 Swift 中 String 类型可以转成 Objective-C 中的 NSString 类型,因此在 Swift 开发过程中可能有如下两种写法:
print("tingPS.characters.count")
// Prints "4"
print("(tingPS as NSString).length")
// Prints "5"
从上述结果可看出,.length 方法得到的字符串长度为5,而 .characters.count 等于4,可能读者会有点懵,同一个字符串怎么计算的长度不一致?其实 .length 与 .characters.count 的计算原理在上文已经做了解释,本小节就简单总结一下:
.length 与 .characters.count 返回值不总是相同的,.length 方法是采用 UTF-16 表示的编码单元为单位进行计算并返回的,即字母 i(U+0069) 、音调符(U+0304)会当做两个字符,因而长度为2。.character.count 的值是通过字形群集界限来确定字符数量的,如还不理解请查看上文。(PS:其实这里也是 Swift 中采用索引的方式访问字符串的原因)
更多内容请访问:http://www.jianshu.com/p/0a8a9f093a72
Swift3.0 中 Strings/Characters 闲聊的更多相关文章
- UICollectionView在Swift3.0中的用法
UICollectionView在Swift3.0中的用法 UICollectionView的初始化跟OC中是相似的,创建 GameView 集成自 UICollectionView .注意不同于UI ...
- Swift3.0中关于日期类的使用指引
日期的处理在大大小小的iOS项目中都十分常见,随着Swift3.0正式版的即将推出,语法的改变让NSDate以及相关类的使用都与之前略有不同,这里将会对基于Swift3.0版本的NSDate及相关类的 ...
- swift3.0 中NSNotification 的使用
swift3.0 有很大变化,其中之一就是NSNotification使用跟原来不一样,以前NSNotification name是String:3.0中定义了一个类型NSNotification.n ...
- Swift3.0变化分享
Swift 3.0 做出的改变很大,在这篇文章中,我将尽我所能,利用代码样例给大家解释Swift 3.0最重要(要命)的改变,希望大家能够做好升级Swift 3.0 的准备.Swift 3.0的改变不 ...
- swift3.0变化总结
Swift 3.0 做出的改变很大,在这篇文章中,我将尽我所能,利用代码样例给大家解释Swift 3.0最重要(要命)的改变,希望大家能够做好升级Swift 3.0 的准备.Swift 3.0的改变不 ...
- Swift2.3 --> Swift3.0 的变化
Swift3.0语法变化 首先和大家分享一下学习新语法的技巧: 用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Synt ...
- Swift3.0都有哪些变化
从写第一篇Swift文章的时候到现在Swift已经从1.2发展到了今天的3.0,这期间由于Swift目前还在发展阶段并不能向下兼容,因此第一篇文章中的部分代码在当前的Xcode环境中已经无法运行.在W ...
- iOS 日期处理 (Swift3.0 NSDate)
处理日期的常见情景 NSDate -> String & String -> NSDate 日期比较 日期计算(基于参考日期 +/- 一定时间) 计算日期间的差异 拆解NSDate ...
- Swift3.0语法变化
写在前面 首先和大家分享一下学习新语法的技巧:用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Syntax- 让Xcod ...
随机推荐
- doxygen 生成源码文档
使用doxygen 生成源代码的文档是相当方便的,本文就简单整理下doxygen的使用说明 1. 安装 关于安装的问题不做特殊的说明,这里直接使用命令安装, 源码安装不做介绍 ubuntu: sudo ...
- iOS开发网络数据之AFNetworking使用 分类: ios技术 2015-04-03 16:35 105人阅读 评论(0) 收藏
http网络库是集XML解析,Json解析,网络图片下载,plist解析,数据流请求操作,上传,下载,缓存等网络众多功能于一身的强大的类库.最新版本支持session,xctool单元测试.网络获取数 ...
- mongodb学习(三) 安装和基本CRUD
菜鸟啊...先吐槽一下自己 发现mongodb已经升级到2.6标准版了. 服务端最新安装方法: http://www.cnblogs.com/lzrabbit/p/3682510.html 一 准备 ...
- Node.js timer的优化故事
前几天nodejs发布了新版本4.0,其中涉及到一个更新比较多的模块,那就是下面要介绍的timer模块. timers: Improved timer performance from porting ...
- UVa 10382 - Watering Grass
题目大意:有一条长为l,宽为w的草坪,在草坪上有n个洒水器,给出洒水器的位置和洒水半径,求能浇灌全部草坪范围的洒水器的最小个数. 经典贪心问题:区间覆盖.用计算几何对洒水器的覆盖范围简单处理一下即可得 ...
- xdebug.var_display_max_data
Xdebug Display Full Details on var_dump() Xdebug is an excellent addition to a PHP developers arsena ...
- vim列编辑
命令模式下:ctrl + v(我在gvim,win7中是ctrl +shift + q)进入列编辑模,选中要编辑的行(j 上,k下) 输入 “I” (大写的 I,光标定位到选中的第一行),输入要编辑的 ...
- ie6和ie7下z-index bug的解决办法
一.匆匆带过的概念 关于CSS中层级z-index的定义啊什么的不是本文的重点,不会花费过多篇幅详细讲述.这里就简单带过,z-index伴随着层的概念产生的.网页 中,层的概念与photoshop或是 ...
- bmp图片显示
文件IO项目: 在开发板屏幕上循环显示目录里的图片 a.按照一定的间隔循环显示目录里的bmp图片 b.实现手指滑动来显示目录里的图片(bmp,jpg)上一张,下一张 d1: 1.能操控屏幕(查询开发板 ...
- Carthage - 一个简单、去集中化的Cocoa依赖管理器
作为一名新时代的90后猿 在swift大势所趋的时候 怎能不会Carthage 配置它其实很简单 下面我们一步一步来 (1)打开你的终端 输入 brew update brew install c ...