我一直在用 Swift 3 更新我的一些旧代码和答案,但是当我使用 Swift 字符串和子字符串索引时,事情变得混乱了。
具体来说,我正在尝试以下操作:
let str = "Hello, playground" let prefixRange = str.startIndex..<str.startIndex.advancedBy(5) let prefix = str.substringWithRange(prefixRange)
第二行给了我以下错误
“String”类型的值没有成员“substringWithRange”
我看到现在String确实有以下方法:
String
str.substring(to: String.Index) str.substring(from: String.Index) str.substring(with: Range<String.Index>)
起初这些真的让我很困惑,所以我开始玩index 和 range。这是子字符串的后续问题和答案。我在下面添加一个答案来展示它们是如何使用的。
以下所有示例都使用
var str = "Hello, playground"
字符串在 Swift 4 中进行了相当大的改革。当你现在从 String 中获取一些子字符串时,你会得到一个Substring类型而不是String. 为什么是这样?字符串是 Swift 中的值类型。这意味着如果您使用一个字符串来创建一个新字符串,则必须将其复制过来。这有利于稳定性(没有其他人会在你不知情的情况下更改它)但不利于效率。
Substring
另一方面,子字符串是对它所来自的原始字符串的引用。这是说明这一点的文档中的图像。
无需复制,因此使用效率更高。但是,假设您从一百万个字符的字符串中得到了一个十字符的子字符串。因为 Substring 正在引用 String,所以只要 Substring 存在,系统就必须保留整个 String。因此,每当您完成对子字符串的操作时,将其转换为字符串。
let myString = String(mySubstring)
这将只复制子字符串,并且可以回收保存旧字符串的内存。子字符串(作为一种类型)是短暂的。
Swift 4 的另一个重大改进是字符串是集合(再次)。这意味着您可以对集合执行任何操作,也可以对字符串执行任何操作(使用下标、迭代字符、过滤器等)。
以下示例展示了如何在 Swift 中获取子字符串。
您可以通过使用下标或许多其他方法(例如,、、、)从字符串中获取prefix子suffix字符串split。但是,您仍然需要使用String.Index而不是Int范围的索引。
prefix
suffix
split
String.Index
Int
您可以使用下标(注意 Swift 4 单边范围):
let index = str.index(str.startIndex, offsetBy: 5) let mySubstring = str[..<index] // Hello
或prefix:
let index = str.index(str.startIndex, offsetBy: 5) let mySubstring = str.prefix(upTo: index) // Hello
甚至更简单:
let mySubstring = str.prefix(5) // Hello
使用下标:
let index = str.index(str.endIndex, offsetBy: -10) let mySubstring = str[index...] // playground
或suffix:
let index = str.index(str.endIndex, offsetBy: -10) let mySubstring = str.suffix(from: index) // playground
let mySubstring = str.suffix(10) // playground
请注意,当使用 时,suffix(from: index)我必须使用-10. 仅使用 时不需要这样做,它只使用字符串suffix(x)的最后一个x字符。
suffix(from: index)
-10
suffix(x)
x
我们再次在这里简单地使用下标。
let start = str.index(str.startIndex, offsetBy: 7) let end = str.index(str.endIndex, offsetBy: -6) let range = start..<end let mySubstring = str[range] // play
不要忘记,当您准备好保存子字符串时,应将其转换为 aString以便清理旧字符串的内存。
在阅读了Airspeed Velocity 和 Ole BegemannInt的文章 Strings in Swift 3 之后,我犹豫是否要使用基于索引的扩展。尽管在 Swift 4 中,字符串是集合,但 Swift 团队故意没有使用Int索引。它仍然是String.Index。这与由不同数量的 Unicode 代码点组成的 Swift 字符有关。必须为每个字符串唯一地计算实际索引。
不得不说,我希望 Swift 团队String.Index在未来能找到一种抽象的方式。但在他们之前,我选择使用他们的 API。它帮助我记住字符串操作不仅仅是简单的Int索引查找。