String.Index如何在Swift中工作

我一直在更新一些旧的代码和Swift 3的答案,但是当我到Swift的string和索引,这是一个很难理解的东西。

具体来说我正在尝试以下内容:

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

第二行给了我下面的错误

'advancedBy'不可用:要通过n个步骤前进一个索引,在产生索引的CharacterView实例上调用'index(_: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) 

起初我真的很困惑,于是我开始和他们一起玩,直到我理解他们。 我在下面添加一个答案,以显示如何使用它们。

在这里输入图像说明

以下所有示例都使用

 var str = "Hello, playground" 

startIndexendIndex

  • startIndex是第一个字符的索引
  • endIndex是最后一个字符之后的索引。

 // 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的单向范围 ,范围可以简化为以下forms之一。

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

为清晰起见,我将在下面的示例中使用完整的forms,但为了便于阅读,您可能希望在代码中使用单侧范围。

after

如在: index(after: String.Index)

  • after是指给定索引后的字符索引。

例子

 // 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是指给定索引之前的字符索引。

例子

 // 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.IndexDistancetypes,但可以给它一个Int

例子

 // 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语句将被跳过。

为什么需要String.Index?

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

这可能是隐藏在Int索引扩展的后面,但我不愿意这么做。 提醒一下实际发生的事情是很好的。