Tested on GitHub Actions

Swift 5 swift package manager 5.2 is supported Supports macOS, iOS, tvOS, watchOS, Linux, & Windows

Swift 字符串整数访问

我讨厌 Swift String 不允许你使用 Int 来访问它们的字符。这个包改变了这一点。

someString[someString.index(someString.startIndex, offsetBy: 2) ... someString.index(someString.startIndex, offsetBy: 5)]

变为这样:

import StringIntegerAccess

var someString = "Hello, World!"

someString[1...4] // "ello"
someString[7..<12] = "Mars" // "Hello, Mars!"

安全性

如果您愿意,您还可以放心,无论您传递什么整数,它都不会崩溃!从 2.0.0 版本开始,您现在可以使用 [orNil:] 下标,它将返回与常规下标相同的值,但是如果您给它们超出范围的索引,它们将返回 nil 而不是崩溃。

import SafeStringIntegerAccess

var someString = "Hello, World"

someString[orNil: 3..<5] == "lo"
someString[orNil: 3..<5] == someString[3..<5]
someString[orNil: 42..<99] == nil 
someString[orNil: -10 ..< -5] == nil 


someString[orNil: 7...]   = "Mars!"      // "Hello, Mars!"
someString[orNil: 999...] = "Boundaries" // "Hello, Mars!"

更棒的是,这也隐式导入了 StringIntegerAccess,因此您不必重复导入!

性能

这与它缩短的长形式**性能完全相同**。也就是说,长形式通常性能不是很高。正如 Rob Napier 在 StackOverflow 上指出的,由于 Swift String 元素是 Unicode 字符,并且 Unicode 字符是长度不确定的码位,并且 String 的存储由 UTF-8 码位组成,因此没有简单的方法知道一个字符有多大,所以你不能直接跳到字符串中的任何位置,而必须先读取它之前的所有内容。为了找出“字符 n”,您必须从头开始并解码所有内容,这是 O(n)。

所以你写出这样的代码,感觉非常“安全”

for index in 0..<string.count {
    print(string[index])
}

但实际上这是 O(n^2),这真的很令人惊讶,因为它看起来像是 O(n)。你可能会说“好吧,我的字符串只有 20 个字符长,所以谁在乎”,但我们使用字符串做很多事情,包括多兆字节的 NSTextStorage。(而且这在 Swift 中比其他一些语言扩展得更快,因为 Swift 包括通用算法,其性能承诺依赖于下标操作是 O(1) 这一事实。)

您还可以了解更多关于为什么这样做的信息,在我关于为什么像 👩‍👩‍👧‍👦 这样的表情符号在 Swift String 中受到如此奇怪的对待的 StackOverflow 问题中

"\u{1112}\u{1161}\u{11AB}".contains("\u{1112}") // false

如果您正在解析大型字符串,无论如何您都应该意识到这一点。这里值得指出的是,这种语法糖只是使酸涩后端的接口变得甜美。如果您正在读取和使用大量数据,则应使用 Data 类型,它已经有 Int 下标