第七章——字符串(代码点视图)

本文系阅读阅读原章节后总结概括得出。由于需要我进行一定的概括提炼,如有不当之处欢迎读者斧正。如果你对内容有任何疑问,欢迎共同交流讨论。

有时候我们需要直接对底层的代码点进行一些操作,而不是处理Character,这有以下几个原因。

首先,有时候我们真正需要的就是代码点,比如渲染UTF-8编码的网页或者在与非Swift的API交互中用到了代码点。举个例子,我们看一下NSCharacterSet和Swift中字符串的联合使用。在此前我们说过NSString使用的是UTF-16编码的代码点,所以如果你想用NSCharacterSet来分割字符串,你需要在UTF-16视图中进行:

extension String {
func words(splitBy: NSCharacterSet = .alphanumericCharacterSet()) -> [String] {
return self.utf16.split {
!splitBy.characterIsMember($0)
}.flatMap(String.init)
}
}

let s = "Wow! This contains _all_ kinds of things like 123 and \"quotes\"?"
print(s.words())

// 输出结果:
// ["Wow", "This", "contains", "all", "kinds", "of", "things", "like", "123", "and", "quotes"]
复制代码

具体看一下这段代码的原理。它调用split方法将字符串分割成若干段,分段原理是遇到非数字或字母的字符就分段,分段结果是若干个String.UTF16View的切片,然后再通过flatMap方法转换成字符串,方法的参数是字符串的可失败构造器,这是因为下标有可能落在字符内部的边界上。因此flatMap方法的使用还有助于我们过滤掉所有nil的元素,这在《可选类型技术之旅》中有详细描述。

如果你是用的不是self.utf16而是self.utf8self.utf32,代码无法通过编译。

使用代码点而不是字符的另一个原因是处理代码点比字符快得多。这是因为字符需要组合多个代码点,这需要不断向前寻找有没有可以组合的代码点。在后面的“性能”章节中我们会展示这个速度差异。

最后,UTF-16视图还具有一个其他视图不具备的优点:它可以随机访问。String.UFT16View.Index被拓展,实现了RandomAccessIndexType协议。在上一节中我们知道字符串在String类型的内部正是以UTF-16编码方式存储的。随机访问意味着第n个UFT-16的代码点一定在buffer的第n个位置,无论字符串中是否包含非ASCII码。

你可能认为随机访问很少会派上用场,大多数情况下字符串只需要线性访问。但有一些算法依赖于随机访问以保证其效率。比如Boyer- Moore算法(改良版的KMP) 依赖于随机访问,一次跳过多个字符。你也可以在你的算法中利用上这个特性,比如:

// 貌似原文中没有实现search方法,所以这段代码其实无法编译
let greeting = "Hello, world!"
if let idx = greeting.utf16.search("world".utf16)?.samePositionIn(greeting) {
//     print(greeting[idx..<greeting.endIndex])
}
复制代码

不过这种效率的提示或简便特性的获得是有代价的,现在你的代码无法确保完全是符合Unicode标准的了,所以下面这个断言将会被触发:

let text = "Look up your Pok\u{0065}\u{0301}mon in a Pokédex."
assert(text.utf16.search("Pokémon".utf16) == nil)
复制代码

理论上说,字符串Pok\u{0065}\u{0301}mon和字符串"Pokémon"完全相等,但这里的search方法会返回nil

Unicode标准把变音符和字母连接起来的字符定义为alphanumeric(数字或字母),所以下面这行代码不会出现问题:

print(text.words())

// 输出结果:
// ["Look", "up", "your", "Pokémon", "in", "a", "Pokédex"]
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值