Swift 的range比NSRange更加復雜,并且它在Swift3中并沒有變的更加容易。如果你想更加透徹的明白復雜的原因,你可以閱讀這還有這。我僅僅告訴你如何創建和使用它們。
Closed Ranges: a...b
這個區間表達式創建了一個Swift的range,該表達式包含元素a和元素b,即使可能為某個類型的最大值(例如Int.max
)。關于closed range有兩個類型:CloseRange
和CountableCloseRange
。
-
ClosedRange
該區間的所有元素是可比較的在Swift中(它們遵守Comparable
協議)。
它會允許你訪問一個集合中某區間的元素。代碼示例:
let myRange: ClosedRange = 1...3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c", "d"]
但是,ClosedRange
是不可計算的(它沒有遵守Sequence
協議)。這就意味你不能迭代該區間的值通過一個循環,如果你想循環訪問某個區間的值你需要使用CountableClosedRange
類型。
-
CountableClosedRange
該類型可迭代循環。
//此處換成ClosedRange會報錯
let myRange: CountableClosedRange = 1...3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c", "d"]
for index in myRange {
print(myArray[index])
}
Half-Open Range:a..<b
該區間表達式包含a但不包括b,和上面一樣,它也有兩個不同的類型:Range
和CountableRange
-
Range
和CloseRange
一樣,你可以在一個集合中訪問某區間的元素,示例代碼:
let myRange: Range = 1..<3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c"]
重要的事再說一次,該類型不可應用于for循環語句!
-
CountableRange
該類型可應用于for循環語句
let myRange: CountableRange = 1..<3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c"]
for index in myRange {
print(myArray[index])
}
NSRange
有的時候你仍然需要使用NSRange在Swift(eg:當你創建富文本的時候),所以了解如何創建它也是非常有用的。
let myNSRange = NSRange(location: 3, length: 2)
在這里強調一下上面的表達式代表的是location
和length
,并不是start index
和end index
。上面的例子和Swift中3..<5
看起來非常相似。但是,它倆是不同的,它們并不能互相替換使用。
Ranges with Strings
通過...
和..<
創建ranges是非常方便的方法。代碼示例:
let myRange = 1..<3
比較苦逼的創建方式(作用和上面的代碼是一樣的):
let myRange = CountableRange<Int>(uncheckedBounds: (lower: 1, upper: 3)) // 1..<3
Problem with NSRange
NSRange在截取含有emoji字符的字符串時,會出現錯誤。
代碼示例:
let myNSRange = NSRange(location: 1, length: 3)
let myNSString: NSString = "abcde"
myNSString.substring(with: myNSRange) // "bcd"
let myNSString2: NSString = "a??cde"
myNSString2.substring(with: myNSRange) // "??c" Where is the "d"!?
Swift Solution
由于以上的原因,在Swift中的字符串你需要使用Range<String.Index>
而不是Range<Int>
。String Index的計算是基于一個特殊的string,所以它能識別string中含有emoji或者其他的擴展字體集。
代碼示例:
var myString = "abcde"
let start = myString.index(myString.startIndex, offsetBy: 1)
let end = myString.index(myString.startIndex, offsetBy: 4)
let myRange = start..<end
myString.substring(with: myRange) // "bcd"
myString = "a??cde"
let start2 = myString.index(myString.startIndex, offsetBy: 1)
let end2 = myString.index(myString.startIndex, offsetBy: 4)
let myRange2 = start2..<end2
myString.substring(with: myRange2) // "??cd"