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"