Bạn không phải là người duy nhất không thể tìm ra giải pháp.
String
không thực hiện RandomAccessIndexType
. Có lẽ bởi vì chúng cho phép các ký tự có độ dài byte khác nhau. Đó là lý do tại sao chúng ta phải sử dụng string.characters.count
( count
hoặc countElements
trong Swift 1.x) để có được số lượng ký tự. Điều đó cũng áp dụng cho các vị trí. Đây _position
có lẽ là một chỉ mục vào mảng byte thô và họ không muốn phơi bày điều đó. Điều String.Index
này có nghĩa là để bảo vệ chúng ta khỏi việc truy cập byte ở giữa các ký tự.
Điều đó có nghĩa là bất kỳ chỉ mục nào bạn nhận được phải được tạo từ String.startIndex
hoặc String.endIndex
( String.Index
thực hiện BidirectionalIndexType
). Bất kỳ chỉ số khác có thể được tạo bằng cách sử dụng successor
hoặc predecessor
phương pháp.
Bây giờ để giúp chúng tôi với các chỉ mục, có một bộ phương thức (các hàm trong 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
Làm việc với String.Index
rất cồng kềnh nhưng sử dụng trình bao bọc để lập chỉ mục theo số nguyên (xem https://stackoverflow.com/a/25152652/669586 ) là nguy hiểm vì nó che giấu sự không hiệu quả của việc lập chỉ mục thực.
Lưu ý rằng việc triển khai lập chỉ mục Swift có vấn đề là các chỉ số / phạm vi được tạo cho một chuỗi không thể được sử dụng một cách đáng tin cậy cho một chuỗi khác , ví dụ:
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]