Swift Range
Created by 大刘 liuxing8807@126.com
参考:
Swift(5)的Range代表一个范围区间(interval, lowerBound...upperBound), 是一个结构体对象, 它和NSRange不同,不可强转
@frozen struct Range<Bound> where Bound : Comparable
// 0.0..<5.0 0到5,但不包括5:[0, 5)
// 0.0..<5.0: Half Open Range Operator [0, 5)
// 0.0...5.0: Closed Range (lowerBound...upperBound) [0,5]
let underFive = 0.0..<5.0
print(underFive.contains(0.0)) // true
print(underFive.contains(3.14)) // true
print(underFive.contains(6.28)) // false
print(underFive.contains(5.0)) // false
Range可以表示“空范围”,即范围区间为0
let empty = 0.0..<0.0
print(empty.contains(0.0)) // false
print(empty.isEmpty) // true
如果Range的区间内容是整型(或者遵守了Strideable协议),可以使用for-in遍历Range, 此时Range就作了为一个集合使用(Using a Range as a Collection of Consecutive Values)
for n in 3..<5 { // ..<是一个函数
print(n)
//3
//4
}
One side range
let range = ..<2
print(range.contains(-1)) // true
print(range.contains(-8)) // true
//print(range.contains(-8.0)) // Cannot convert value of type 'Double' to expected argument type 'Int'
print(range.contains(2)) // false
根据Range截取字符串
SubString, 此文很详细所以照搬
subString(with:)方法被废弃,原来的NSString的subStringWithRange很好用,但在Swift中不支持,这是有原因的:
Swift Programming Language Guide:
In String, different characters can require different amounts of memory to store, so in order to determine which Character is at a particular position, you must iterate over each Unicode scalar from the start or end of that String. For this reason, Swift strings can’t be indexed by integer values.
One way we can access the individual Character values for a String is by iterating over the string with a for-in loop:
for character in "hello" {
print(character)
}
Output:
// h
// e
// l
// l
// o
Another way to efficiently access range of characters in String is to use Range based subscript. Ranges in Swift allow us to select parts of Strings, collections, and other types.
There is difference between workings of Range and NSRange.
There will be situations where we come across NSRange in Swift. For example NSTextCheckingResult returned from regular expression match gives NSRange.
看一个使用NSRange的问题:
NSString *testString = @"1234567";
NSRange range = NSMakeRange (3, 3);
NSLog (@"substring: %@\n\n", [testString substringWithRange:range]);
打印 456, OK, 但是:
NSString *str = @"hello⛳️😃❤️";
NSLog(@"%ld", str.length); // 11
// 可以发现, length并不是字符串的字符个数
range也是一样的:
NSString *testString = @“Cat!🐱!!”;
NSRange range = NSMakeRange (3, 3);
NSLog (@“substring: %@”, [testString substringWithRange:range]);
// Expected: !🐱!
// Actually returns: !🐱
// Different characters in strings can require different amounts of memory to store.
In above example NSRange is using absolute Int based subscript to get us substring. Cat emoji from example use more space than regular character so it returns only 2 characters instead of expected 3 characters. This phenomenon marks one of the important differences in the workings of Range and NSRange. This is also the reason why we no longer access character or substring from String with Int based subscript in Swift:
let testString = "hello"
testString[2]
will give an error:
'subscript(_:)' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion
String Indices
In Swift to avoid above unreliable extraction of characters - we have String Indices
<table>
<tr>
<td>startIndex</td>
<td>startIndex is the index of the first character.</td>
</tr>
<tr>
<td>endIndex</td>
<td>endIndex is the index after the last character.
</td>
</tr>
</table>
let testString = "hello"
print(testString[testString.startIndex]) // h
print(testString[testString.index(before: testString.endIndex)]) // o
let testString2 = "Cat!🐱!!"
print(testString2[testString2.startIndex]) // C
print(testString2[testString2.index(before: testString2.endIndex)]) // !
In above code example We didn’t use endIndex directly in subscript because endIndex is position out of bounds in our string. endIndex is the index after the last character. Hence we used .index(before: .endIndex)
let testString = "Cat!🐱!!"
let startIndex = testString.index(testString.startIndex, offsetBy: 3)
let endIndex = testString.index(testString.endIndex, offsetBy: -1)
let range: Range = startIndex..<endIndex
print(testString[range])
// Expected: !🐱!
// Actually returns: !🐱!
You must have noticed: In Swift we didn’t use substring(with: <Range <String.Index >)
Note:
substring(with:)’ is deprecated: Please use String slicing subscript.
In Swift 5 this function is deprecated and recommend us to use slicing subscript. We use testString[range]
NSRange don’t work in Swift subscript. We need to convert NSRange to Range.
let testString = "Cat!🐱!!"
let nsRange: NSRange = NSMakeRange (3, 3);
let swiftRange = Range(nsRange, in: testString)
print(testString[swiftRange!]) // !🐱
// just as [testString substringWithRange:range], we get !🐱
// 少了一个!
Substring
注意通过Range获取到的字符串并不是String, 而是Substring, Substring同样实现了 StringProtocol 协议,Doc