Swift中蝠嘉,字符串是不能使用整數(shù)索引的世吨,比如下面的代碼會(huì)報(bào)錯(cuò):
let name = "Neil"
name[2]
// 'subscript(_:)' is unavailable: cannot subscript String with an Int, use a String.Index instead.
這是為什么呢? 簡(jiǎn)單的回答是:Swift認(rèn)為字符串是由一個(gè)個(gè)字形群集 (grapheme clusters)組成的,字形群集的大小不固定所以不能用整數(shù)去索引 (字形群集其實(shí)就是Swift中的Character(字符)類).
我們先看看蘋果是怎么定義字形群集的:
An extended grapheme cluster is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character.*
意思就是Swift中一個(gè)字符 (一個(gè)字形群集) 可以由一個(gè)或者多個(gè)unicode scalar組成. 比如:
let letterNorml = "é"
let letterCombining = "e\u{0301}"
for code in letterNorml.unicodeScalars {
print(code.value)
}
// 233
for code in letterCombining.unicodeScalars {
print(code.value)
}
// 101
// 769
這里了 letterNorml
字符串只有一個(gè)unicode scalar (233) 而 letterConbining
字符串有兩個(gè)unicode scalar (101 和 769).
但他們是相等的:
print(letterNorml == letterCombining) // true
他們的字符(字形群集)數(shù)量相等蔬蕊,都只有一個(gè):
print(letterNorml.count) // 1
print(letterCombining.count) // 1
但unicode scalars的數(shù)量不同:
print(letterNorml.unicodeScalars.count) // 1
print(letterCombining.unicodeScalars.count) // 2
因?yàn)檫@樣,不同的字符可能需要不同數(shù)量的unicode. 比如上面的例子, 有的字母需要兩個(gè)unicodes. 有的表情甚至需要4個(gè)unicodes.
這樣導(dǎo)致一個(gè)字符需要變長(zhǎng)度的內(nèi)存空間存儲(chǔ),讓索引變得困難逻锐。下面解釋為什么:
如果一個(gè)字符是固定長(zhǎng)度的,比如4個(gè)字節(jié)雕薪,想要找到一個(gè)字符串中位置i的字符昧诱,只需要把字符串的起始位置加上4*i就行,時(shí)間復(fù)雜度是O(1)所袁。
然而盏档,如果一個(gè)字符是變長(zhǎng)度的,那我們必須從頭遍歷字符串中所有的unicode scalar來(lái)確定某個(gè)字符的位置燥爷,最壞情況的時(shí)間復(fù)雜度是O(n)
由于這個(gè)原因蜈亩,Swift字符串不能有整數(shù)去索引
Swift字符串的索引方法
我們需要用String.Index類型來(lái)索引字符串:
let name = "Neil"
let index = name.index(name.startIndex, offsetBy: 2)
let char = name[index] // i
用Range類型來(lái)獲得子字符串:
let name = "Neil"
let index1 = name.index(name.startIndex, offsetBy: 1)
let index2 = name.index(name.startIndex, offsetBy: 3)
let indexRange = index1...index2
let subString = name[indexRange] // eil