前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS一点点 - Swift 标准库中的 String

iOS一点点 - Swift 标准库中的 String

作者头像
Alan Zhang
发布2018-10-19 14:51:43
8580
发布2018-10-19 14:51:43
举报
文章被收录于专栏:Alan's Lab

参考资料

Swift Standard Library Reference 主体为对该链接 String 部分理解基础上的翻译,但有较大改动且加入更多个人见解与扩展内容 Unicode and you by BetterExplained BetterExplained对于Unicode的解释,随手找的 ?? ~ emoji unicode characters ~ ??

所有我不能确定标准与否的术语翻译,均会在第一次出现时于括号内标注原文。

可能稍显啰嗦,我是希望能够借助尽量 细致、直观、全面、有理有据 的讲解,来提升自己的理解,相信也能帮到其他人。我很喜欢读这种态度的文章,也希望自己的文章能有这种水平,希望你也喜欢。

正文

Swift 标准库提供了 String 文本类型,适用 Unicode 文本。本文内容就是,如何对它进行定位(index)和切分(slice)。

先看下面的例子

代码语言:javascript
复制
let str = "Héllo, ??laygr?und!"

let badRange = 4...12
// str[badRange]
// 取消上行的注释将会看到一个错误 “Subscript is unavailable: cannot subscript String with a range of Int”

不能用 Int 定义的 Range 范围来取子串,为毛? 字符串的第 n 个位置存第 n 个字 这样的逻辑有什么问题?为了理解 Swift 这样设计的目的,下面要简单扯下字符集。

C语言的字符串是这样的

01000001

01000010

01000011

01000100

A

B

C

D

一个字节存一个字符,第 n 个字节存第 n 个字符,没问题。但是 Unicode 可以表示的字符很多,一个字节表示不完。于是要用更多字节表示一个字符,但 ASCII 中 ABCD 这些字符只要一个字节就够了,在这里也要统一用多个字节就会造成浪费。因此有了变长编码如 UTF-8 ,一些字符用一字节表示,另一些用多个字节。如字符串 "A??" ,utf-8的表示如下

01000001

11110000 …这里省略6个字节,呵呵呵… 10111000

A

??

一个有趣的细节: UTF-8 的 “A” 和 前面 ASCII 的 “A” 编码一致,都是 65 。实际上不止是 “A” ,UTF-8 是兼容 ASCII 的,所有 ASCII 内的字符的在 UTF-8 和 ASCII 中的表示都一样,也即都是占一个字节

另一个有趣的细节。。。: UTF-8 一个字符使用的最多是 4 个字节而不是 8 个,“??” 符号其实是由两个地区标记符(regional indicator symbol letter)“u” 和 “s” 拼起来的,所以才用了 8 字节。 这里的地区标记符 “u” 和 “s” 不是英文字母,是专门用来拼装国家、地区标记的特殊字符。从它们占用了 4 个字节而不是 ASCII 的 1 字节这里也可以看出来区别

表示 “A” 只用一个字节,表示 “??” 却用了足足八个字节。这就破坏了上表中字节和字符一一对应的关系,数据结构中的第 n 位和字符串的第 n 个字符之间的对应关系没了。

前面我们说过 Swift 标准库提供的 String 用的是 Unicode ,现在再回去看前面那句报错 Subscript is unavailable: cannot subscript String with a range of Int 就知道了。不能用 Int 指定的范围来定位、切分字符串的原因就是因为,由于使用了变长编码,导致 String 的数据结构的第 n 个元素,不是我们要的第 n 个字符。(姑且先这么说吧)

String 中要定位、切分字符串,需要使用 String.Index 对象提供的一系列方法,它们会确保操作以字符为单位进行,不会出现让你把一个多字节字符砍成两半的问题:

代码语言:javascript
复制
// successor() 下一个字符
str[str.startIndex]                            // "H"
str[str.startIndex.successor()]                // "é"
str[str.startIndex.successor().successor()]    // "l"

// predecessor() 上一个字符
str[str.endIndex.predecessor()]                // "!"
str[str.endIndex.predecessor().predecessor()]  // "d"

// advancedBy(Int) 与按给定次数执行前两个方法效果相同
str[str.startIndex.advancedBy(7)]              // 与执行七次 successor() 效果相同 "??"
str[str.endIndex.advancedBy(-7)]               // 与执行七次 predecessor() 效果相同 "g"

// 此处创建的 Range 是 Range<Index> 类型,而非 Range<Int>
let range = str.startIndex.advancedBy(4)...str.startIndex.advancedBy(12)
str[range]                                     // "o, ??laygr"

上面是相关的常用用法。

至此,这部分的学习就暂时告一段落了,关于 String 的其它内容,以后遇到再谈。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 参考资料
  • 正文
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档