解決策を見つけられなかったのはあなただけではありません。
String
実装していませんRandomAccessIndexType
。おそらく、異なるバイト長の文字を使用できるためです。これが、文字数を取得するためにstring.characters.count
(count
またはcountElements
Swift 1.xで)使用する必要がある理由です。それはポジションにも適用されます。これ_position
はおそらくバイトの生の配列へのインデックスであり、彼らはそれを公開したくありません。これString.Index
は、文字の途中のバイトにアクセスできないようにするためのものです。
つまり、取得するインデックスは、String.startIndex
またはString.endIndex
(String.Index
implements BidirectionalIndexType
)から作成する必要があります。その他のインデックスは、successor
またはpredecessor
メソッドを使用して作成できます。
インデックスを支援するために、一連のメソッド(Swift 1.xの関数)があります。
Swift 4.x
let text = "abc"
let index2 = text.index(text.startIndex, offsetBy: 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let characterIndex2 = text.index(text.startIndex, offsetBy: 2)
let lastChar2 = text[characterIndex2] //will do the same as above
let range: Range<String.Index> = text.range(of: "b")!
let index: Int = text.distance(from: text.startIndex, to: range.lowerBound)
Swift 3.0
let text = "abc"
let index2 = text.index(text.startIndex, offsetBy: 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let characterIndex2 = text.characters.index(text.characters.startIndex, offsetBy: 2)
let lastChar2 = text.characters[characterIndex2] //will do the same as above
let range: Range<String.Index> = text.range(of: "b")!
let index: Int = text.distance(from: text.startIndex, to: range.lowerBound)
Swift 2.x
let text = "abc"
let index2 = text.startIndex.advancedBy(2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let lastChar2 = text.characters[index2] //will do the same as above
let range: Range<String.Index> = text.rangeOfString("b")!
let index: Int = text.startIndex.distanceTo(range.startIndex) //will call successor/predecessor several times until the indices match
Swift 1.x
let text = "abc"
let index2 = advance(text.startIndex, 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let range = text.rangeOfString("b")
let index: Int = distance(text.startIndex, range.startIndex) //will call succ/pred several times
での作業String.Index
は面倒ですが、ラッパーを使用して整数でインデックスを作成します(https://stackoverflow.com/a/25152652/669586を参照))、実際のインデックス作成の非効率性が隠されるため危険です。
Swiftインデックス実装には、ある文字列に対して作成されたインデックス/範囲を別の文字列に対して確実に使用できないという問題があることに注意してください。次に例を示します。
Swift 2.x
let text: String = "abc"
let text2: String = "🎾🏇🏈"
let range = text.rangeOfString("b")!
//can randomly return a bad substring or throw an exception
let substring: String = text2[range]
//the correct solution
let intIndex: Int = text.startIndex.distanceTo(range.startIndex)
let startIndex2 = text2.startIndex.advancedBy(intIndex)
let range2 = startIndex2...startIndex2
let substring: String = text2[range2]
Swift 1.x
let text: String = "abc"
let text2: String = "🎾🏇🏈"
let range = text.rangeOfString("b")
//can randomly return nil or a bad substring
let substring: String = text2[range]
//the correct solution
let intIndex: Int = distance(text.startIndex, range.startIndex)
let startIndex2 = advance(text2.startIndex, intIndex)
let range2 = startIndex2...startIndex2
let substring: String = text2[range2]