我一直在使用 Swift 3 更新我的一些旧代码和答案,但是当我使用 Swift 字符串和子字符串索引时,事情变得困惑了。
具体来说,我正在尝试以下操作:
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)
第二行给我以下错误
Value of type 'String' has no member 'substringWithRange'
我看到 String
现在确实有以下方法:
str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)
一开始这些真的让我很困惑所以我开始玩index and range .这是子串的后续问答。我在下面添加一个答案来展示它们是如何使用的。
最佳答案
以下所有示例均使用
var str = "Hello, playground"
swift 4
字符串在 Swift 4 中得到了相当大的改进。当你现在从字符串中获取一些子字符串时,你得到的是 Substring
类型而不是 String
。为什么是这样?字符串是 Swift 中的值类型。这意味着如果您使用一个 String 来创建一个新的,则必须将其复制过来。这有利于稳定性(没有人会在您不知情的情况下更改它)但不利于效率。
另一方面,子字符串是对其来源的原始字符串的引用。这是来自 documentation 的图片说明这一点。
无需复制,使用效率更高。但是,假设您从一百万个字符的字符串中得到了一个十个字符的子字符串。因为 Substring 正在引用 String,所以只要 Substring 存在,系统就必须保留整个 String。因此,无论何时完成对子字符串的操作,都将其转换为字符串。
let myString = String(mySubstring)
这将只复制子字符串,保存旧字符串的内存可以是 reclaimed .子字符串(作为一种类型)是短暂的。
Swift 4 的另一大改进是字符串是集合(再次)。这意味着无论您可以对 Collection 做什么,您也可以对 String 做什么(使用下标、遍历字符、过滤器等)。
以下示例展示了如何在 Swift 中获取子字符串。
获取子字符串
您可以使用下标或许多其他方法(例如,prefix
、suffix
、split
)从字符串中获取子字符串).不过,您仍然需要为范围使用 String.Index
而不是 Int
索引。 (如果您需要这方面的帮助,请参阅 my other answer。)
字符串的开始
您可以使用下标(注意 Swift 4 单边范围):
let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello
或前缀
:
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
或后缀
:
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
将子字符串
转换为字符串
不要忘记,当您准备好保存子字符串时,您应该将其转换为 String
以便清理旧字符串的内存。
let myString = String(mySubstring)
使用 Int
索引扩展?
阅读文章 Strings in Swift 3 后,我犹豫要不要使用基于 Int
的索引扩展由 Airspeed Velocity 和 Ole Begemann 提供。尽管在 Swift 4 中,字符串是集合,但 Swift 团队有意没有使用 Int
索引。它仍然是 String.Index
。这与由不同数量的 Unicode 代码点组成的 Swift 字符有关。必须为每个字符串计算唯一的实际索引。
我不得不说,我希望 Swift 团队在未来找到一种方法来抽象掉 String.Index
。但在那之前,我选择使用他们的 API。它帮助我记住,字符串操作不仅仅是简单的 Int
索引查找。
关于swift - String 子字符串如何在 Swift 中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39677330/