Swift 4 String

Swift的字符串和OC有很大差别,下面详细学习下。

Grapheme Clusters (字形簇)

As you know, a string is made up of a collection of Unicode characters. Until now, you have considered one code point to precisely equal one character, and vice versa. However the term "character" is fairly loose.

就我们目前所知道的,字符串是由一连串的Unicode字符组成。于此同时,我们也是通过一个代码点来直接判断两个字符是否相等,反之亦然。但是,"character"其实概念是相当松散的。

直入主题,在swift中我们表示cafe可以有两种方式:
“ One example is the é in café, 其中é用unicode编码单独表示是233,如果用combining character的形式就是e+声调的形式,e是101,声调是769,而后者这种方式就是Unicode标准中的字形簇。在swift中字形簇用Character来表示。

可能上面的解释还不够清楚解释字形簇在swift的中意义,下面看个例子:

let cafeNormal = "café"
let cafeCombining = "cafe\u{0301}"

cafeNormal.count     // 4
cafeCombining.count  // 4

\u表示的是Unicode的速记法书写形式,我们可以用Unicode速记法书写任意形式的Unicode编码。这里为啥不直接写呢,因为键盘上敲不出来e加声调的字符。

可以看到代码二者的输出长度一致,为什么呢?因为在Swift中,string是被看做字形簇的一个集合,e加声调就是一个字形簇,所以这里长度输出都是4。

上面的结果意味着我们要花费一个线性的时间去找出字符串的长度,因为我们要逐个遍历字符串去找出有多少个字形簇。所以,我们不能简单的通过内存中长度来判断这个字符串有多大。

挺麻烦的吧,所以最后swift给我们提供了unicodeScalars这种方式来访问string的底层Unicode数据:

cafeNormal.unicodeScalars.count     // 4
cafeCombining.unicodeScalars.count  // 5
for codePoint in cafeCombining.unicodeScalars {
  print(codePoint.value)
}

输出结果:

99
97
102
101
769

Indexing strings(字符串索引)

在Swift中,我们无法通过下标来直接访问字符串的具体字符,为啥呢?因为Swift需要我们关注下string的底层原理,原理是啥?就是我们上面说的字形簇。所以,字符串索引访问的方式就比较蛋疼了,我们只能够使用特殊的字符串索引类型而不是整形的下标类型来访问。

let firstIndex = cafeCombining.startIndex

这里firstIndex的数据类型就是String.Index类型。这里我们只是拿到了索引,具体访问:

let firstChar = cafeCombining[firstIndex]

firstChar结果就是c。

下面,我们尝试访问结尾的字符:

let lastIndex = cafeCombining.endIndex
let lastChar = cafeCombining[lastIndex]

但是,错误出现了

fatal error: Can't form a Character from an empty String

为啥呢?原因就是终结索引实际上是在字符串结尾的1,(let cafeCombining = "cafe\u{0301}")。所以,我们需要这么做:

let lastIndex = cafeCombining.index(before: cafeCombining.endIndex)
let lastChar = cafeCombining[lastIndex]

也可以这么做:

let fourthIndex = cafeCombining.index(cafeCombining.startIndex, offsetBy: 3)
let fourthChar = cafeCombining[fourthIndex]

Equality with combining characters (如何判断组合字符是否相等)

Swift采用一种叫canonicalization(规范化)的技术来处理象形字符之间的比较,和传统的其他语言逐个字符比较,然后判断是否都相等不同。Swift首先对字符串进行规范化操作,让2个字符串变成同一种风格,然后再逐个进行比较,具体的实现方式我们不必关注,了解这个特性即可。

let equal = cafeNormal == cafeCombining

在Swift中,上面代码的执行结构是true.

Strings as bi-directional collections(字符串作为双向集合)

Swift做了一些内存优化,双向集合就是一种,其实概念很简单,看下代码就知道了。

let name = "Matt"
let backwardsName = name.reversed()

backwardsName的类型是string吗?不是,其实在swift中它是 reversed collection 类型,Swift做了内存优化,他还是指向源字符串的内存空间。但是,使用起来和其他字符串并无差别。

let secondCharIndex = backwardsName.index(backwardsName.startIndex, offsetBy: 1)
let secondChar = backwardsName[secondCharIndex] // "t”

如果你确实想要开辟一块新空间,那么这么做:

let backwardsNameString = String(backwardsName)

Substrings (子串)

首先,我们来看一段代码:

let fullName = "Matt Galloway"
let spaceIndex = fullName.index(of: " ")!
let firstName = fullName[fullName.startIndex..<spaceIndex] // "Matt”
  • open-ended range (开放范围)
    Swift提供了一种新的范围类型:开放范围。我们只需要提供一个索引位置,而另一个索引则被默认假设为集合的开始或结尾,类似于数学中的开闭区间。

应用这个类型,我们可以将上面的代码修改如下:

let firstName = fullName[..<spaceIndex]
let lastName = fullName[fullName.index(after: spaceIndex)...]

细心点,我们可以发现这时firstName的数据类型是Substring而不是string类型,这里其实和reversed string是一个原理,Swift本身是做了内存优化的,如果你想要一个全新string那么就这么做:

let lastNameString = String(lastName)

看到这里,我们不禁会想,为什么Swift的设计者要以这么复杂的方式来处理字符串呢?其实Substring在swift中是一个很巧妙的设计。Substring分享父string的内存,这就意味着我们处理一个子串时不需要额外的内存开销。然后,当我们确实需要一个string类型的字符串时,我们可以显示的创建一个新的字符串类型,然后内存中的数据就会拷贝到这个新字符串当中。
Swift的设计者本可以默认的让这种拷贝行为执行,但是没有这么做,设计者就是想让你持有substring的类型,然后明确的让你明白这底层到底发生了什么。如果你不是在函数返回值或者函数传参的时候明确的遇到了要求数据类型为string时,你可能都不知道你持有的一直是substring类型的字符串,这时,我们就可以用substring类型的字符串来显示的初始化一个string类型的新字符串。
Swift的设计者就是这么固执,但是,设计者这么严谨的使用字符串就是告诉我们,字符串使用很频繁,而且处理起来很复杂,这点在日后编码中是很重要的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • String在Swift 4 的新特性深受大众喜爱(至少我是很喜欢的).String API 在Swift 4 中...
    Lucky闪闪星阅读 718评论 0 1
  • 删掉重新来一次吧,记得改那个脚本修改 /home/ubuntu/eos/scripts/install_depen...
    卢衍泓阅读 1,042评论 0 1
  • 冲动之下,成功加到微信,“叮”的一声,手机铃声表对方已通过你的验证要求,谁也没有先说话,哼,就看谁先忍不住。
    爱天蓝QG阅读 130评论 1 0
  • 喜欢在路上 欣赏一闪而过风景 特别是行走在深谷大桥上 脚下沟壑纵横 远处山岚雾霭 晴天洋溢着活泼 雨天诉说着多情 ...
    凡木有心阅读 174评论 0 0
  • 逢人便说:“我微信红包被人偷了278元,我卡里面的钱会不会也会被偷走。”结果有人说:“微信和卡不一样。”但是我还是...
    田萍阅读 130评论 0 2