小编典典

字符串子字符串在 Swift 中是如何工作的

all

我一直在用 Swift 3 更新我的一些旧代码和答案,但是当我使用 Swift 字符串和子字符串索引时,事情变得混乱了。

具体来说,我正在尝试以下操作:

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)

第二行给了我以下错误

“String”类型的值没有成员“substringWithRange”

我看到现在String确实有以下方法:

str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)

起初这些真的让我很困惑,所以我开始玩index 和
range
。这是子字符串的后续问题和答案。我在下面添加一个答案来展示它们是如何使用的。


阅读 123

收藏
2022-03-16

共1个答案

小编典典

在此处输入图像描述

以下所有示例都使用

var str = "Hello, playground"

斯威夫特 4

字符串在 Swift 4 中进行了相当大的改革。当你现在从 String
中获取一些子字符串时,你会得到一个Substring类型而不是String. 为什么是这样?字符串是 Swift
中的值类型。这意味着如果您使用一个字符串来创建一个新字符串,则必须将其复制过来。这有利于稳定性(没有其他人会在你不知情的情况下更改它)但不利于效率。

另一方面,子字符串是对它所来自的原始字符串的引用。这是说明这一点的文档中的图像。

无需复制,因此使用效率更高。但是,假设您从一百万个字符的字符串中得到了一个十字符的子字符串。因为 Substring 正在引用 String,所以只要
Substring 存在,系统就必须保留整个 String。因此,每当您完成对子字符串的操作时,将其转换为字符串。

let myString = String(mySubstring)

这将只复制子字符串,并且可以回收保存旧字符串的内存。子字符串(作为一种类型)是短暂的。

Swift 4 的另一个重大改进是字符串是集合(再次)。这意味着您可以对集合执行任何操作,也可以对字符串执行任何操作(使用下标、迭代字符、过滤器等)。

以下示例展示了如何在 Swift 中获取子字符串。

获取子字符串

您可以通过使用下标或许多其他方法(例如,、、、)从字符串中获取prefixsuffix字符串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字符。

字符串中的范围

我们再次在这里简单地使用下标。

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

转换SubstringString

不要忘记,当您准备好保存子字符串时,应将其转换为 aString以便清理旧字符串的内存。

let myString = String(mySubstring)

使用Int索引扩展?

在阅读了Airspeed Velocity 和 Ole BegemannInt的文章 Strings in Swift
3
之后,我犹豫是否要使用基于索引的扩展。尽管在
Swift 4 中,字符串是集合,但 Swift 团队故意没有使用Int索引。它仍然是String.Index。这与由不同数量的 Unicode
代码点组成的 Swift 字符有关。必须为每个字符串唯一地计算实际索引。

不得不说,我希望 Swift 团队String.Index在未来能找到一种抽象的方式。但在他们之前,我选择使用他们的
API。它帮助我记住字符串操作不仅仅是简单的Int索引查找。

2022-03-16