相比OC中的NSRange,在Swift中使用Range是一个比较麻烦的事情,犹记得第一个使用,感觉写法很复杂,这里简单介绍下它的用法。

Close Ragne: a...b

这种操作创建了一个包括a和b的区间,有两种不同的闭区间,CloseRange和CountableClosedRange

  • CloseRange
  • 在Swift中所有Ranges中的元素都是可比的,遵循Comparable协议,这让我们可以获取集合中任意区间的元素

    let myRange: ClosedRange = 1...3
    let myArray = ["a", "b", "c", "d", "e"]
    myArray[myRange] // ["b", "c", "d"]
    
  • CountableClosedRange
  • 它同CloseRange的区别就是它可以遍历,遵循了Sequence协议

    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 Ranges: a..<b

    这是个左闭右开的区间,包括a但是不包括b。同样也有两种不同的类型:Range和CountableRange

  • Range
  • 使用同ClosedRange类似

    let myRange: Range = 1..<3
    let myArray = ["a", "b", "c", "d", "e"]
    myArray[myRange] // ["b", "c"]
    
  • CountableRange
  • let myRange: CountableRange = 1..<3
    let myArray = ["a", "b", "c", "d", "e"]
    myArray[myRange] // ["b", "c"]
    for index in myRange {
        print(myArray[index])
    

    NSRange

    在swift中同样也是需要使用NSRange,因为通过不同的含义来创建的。

    let myNSRange = NSRange(location: 3, length: 2)
    let myRange: Range = 3..<5
    

    它是通过起始位置和长度来确定区间范围,不同于Range通过起始和结束的位置。

    Ranges with Strings

    //Range
    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"
    //NSRange
    let myNSRange = NSRange(location: 1, length: 3)
    let myNSString: NSString = "abcde"
    myNSString.substring(with: myNSRange) // "bcd"
    

    可以看到NSRange比Range要简洁多了,既然这样,为什么苹果还要想出个Range类型呢?

    //Range
    var 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"
    //NSRange
    let myNSString2: NSString = "a😀cde"
    myNSString2.substring(with: myNSRange) // "😀c"    Where is the "d"!?
    

    因为emoji笑脸占用了两个UTF-16单元去存储,所以和我们预期的就有所不同了。

    Extension

    可是要使用String时,Range写法好复杂,该怎么办?这里我们可以拓展String对象。

    extension String {
        subscript(r: ClosedRange<Int>) -> String {
            let start = index(startIndex, offsetBy: r.lowerBound)
            let end = index(startIndex, offsetBy: r.upperBound)
            return self[start...end]
        subscript(r: Range<Int>) -> String {
            get {
                let start = index(startIndex, offsetBy: r.lowerBound)
                let end = index(startIndex, offsetBy: r.upperBound)
                return self[start..<end]
    //usage
    "abcde"[1...3] = "bcd"
    "abcde"[1..<3] = "bc"