我一直在用Swift 3更新我的一些旧代码和答案,但当我使用Swift字符串和索引时,理解这些东西是一件痛苦的事情.

具体来说,我try 了以下几点:

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5) // error

第二行给了我以下错误

"advancedBy"不可用:若要将索引提前n步,请在生成索引的CharacterView实例上调用"index(u:offsetBy:)".

我知道String有以下几种方法.

str.index(after: String.Index)
str.index(before: String.Index)
str.index(String.Index, offsetBy: String.IndexDistance)
str.index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)

一开始我真的很困惑,所以我开始和他们玩,直到我理解他们.我在下面添加了一个答案来说明它们是如何使用的.

推荐答案

enter image description here

以下所有示例都使用

var str = "Hello, playground"

startIndex and endIndex

  • startIndex是第一个字符的索引
  • endIndex是最后一个字符的索引after.

实例

// character
str[str.startIndex] // H
str[str.endIndex]   // error: after last character

// range
let range = str.startIndex..<str.endIndex
str[range]  // "Hello, playground"

使用Swift 4的one-sided ranges,范围可以简化为以下形式之一.

let range = str.startIndex...
let range = ..<str.endIndex

为了清晰起见,我将在下面的示例中使用完整的形式,但为了可读性,您可能希望在代码中使用单边范围.

after

例如:index(after: String.Index)

  • after表示直接在给定索引之后的字符索引.

实例s

// character
let index = str.index(after: str.startIndex)
str[index]  // "e"

// range
let range = str.index(after: str.startIndex)..<str.endIndex
str[range]  // "ello, playground"

before

例如:index(before: String.Index)

  • before指直接在给定索引之前的字符索引.

实例s

// character
let index = str.index(before: str.endIndex)
str[index]  // d

// range
let range = str.startIndex..<str.index(before: str.endIndex)
str[range]  // Hello, playgroun

offsetBy

例如:index(String.Index, offsetBy: String.IndexDistance)

  • offsetBy的值可以是正的,也可以是负的,并且从给定的索引开始.虽然它是String.IndexDistance型的,但你可以给它打Int.

实例s

// character
let index = str.index(str.startIndex, offsetBy: 7)
str[index]  // p

// range
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end
str[range]  // play

limitedBy

例如:index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)

  • limitedBy有助于确保偏移量不会导致索引超出范围.它是一个边界索引.由于偏移量有可能超过限制,因此此方法返回可选值.如果索引超出范围,则返回nil.

实例

// character
if let index = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) {
    str[index]  // p
}

如果偏移量是77而不是7,那么if语句将被跳过.

Why is String.Index needed?

对字符串使用Int索引会更容易.您必须 for each 字符串创建一个新的String.Index的原因是Swift中的字符在引擎盖下的长度不尽相同.单个Swift字符可能由一个、两个或更多Unicode代码点组成.因此,每个唯一字符串必须计算其字符的索引.

可以在Int索引扩展后面隐藏这种复杂性,但我不愿意这样做.提醒自己实际发生的事情是件好事.

Swift相关问答推荐

如何在SwiftUI中创建具有圆角顶部和锯齿状底部边缘的自定义Shape,类似于撕破的纸?

音频播放器无法播放URL音频(操作系统状态错误2003334207.)

如何分解阿拉伯字母?

SwiftUI轨迹绘制怪异

background Task(.backgroundTask)不适用于MySQL

按数组大小进行类型判断?

在Swift中如何用变量计算0.9的立方

使第二个视图变灰 SwiftUI

如何将变量添加到不属于可解码部分的 struct ?

如何在不将变量转换为字符串的情况下判断变量在 Swift 中是否为 Optional(nil)?

如何在 SceneKit 上制作毛玻璃效果

状态变量更改后,SwiftUI 视图不会更改

来自数据的 SwiftUI 图像

如何将使用\u{ea12}创建的 Swift 字符串转换回其十六进制值/字符串ea12?

如何在不阻塞 UI 更新的情况下使用 Swift Concurrency 在后台执行 CPU 密集型任务?

Xcode 7.3 Swift 的语法高亮和代码完成问题

无法推断泛型参数的参数

在 Swift 中以编程方式更新约束的常量属性?

将活动指示器 colored颜色 更改为黑色

快速延迟加载属性