因此,我发现了与将NSRange
转换为Range<String.Index>
相关的问题,但我确实遇到了相反的问题。
很简单,我有一个String
和一个Range<String.Index>
,需要将后者转换为NSRange
以便与较旧的函数一起使用。
到目前为止,我唯一的解决方法就是抓住一个子字符串,如下所示:
func foo(theString: String, inRange: Range<String.Index>?) -> Bool {
let theSubString = (nil == inRange) ? theString : theString.substringWithRange(inRange!)
return olderFunction(theSubString, NSMakeRange(0, countElements(theSubString)))
}
这当然有用,但它不是很漂亮,我宁愿避免不得不抓住一个子串而只是以某种方式使用范围本身,这可能吗?
答案 0 :(得分:10)
如果你查看String.Index
的定义,你会发现:
struct Index : BidirectionalIndexType, Comparable, Reflectable {
/// Returns the next consecutive value after `self`.
///
/// Requires: the next value is representable.
func successor() -> String.Index
/// Returns the previous consecutive value before `self`.
///
/// Requires: the previous value is representable.
func predecessor() -> String.Index
/// Returns a mirror that reflects `self`.
func getMirror() -> MirrorType
}
所以实际上没有办法将它转换为Int
并且这是有充分理由的。根据字符串的编码,单个字符占用不同的字节数。唯一的方法是计算达到所需successor
所需的String.Index
次操作。
修改 String
的定义已经改变了各种Swift版本,但它的答案基本相同。要查看当前的定义,只需通过CMD点击XCode中的String
定义即可到达根目录(也适用于其他类型)。
distanceTo
是一个扩展到各种协议。只需在CMD点击后在String
来源中查找。
答案 1 :(得分:5)
let index: Int = string.startIndex.distanceTo(range.startIndex)
答案 2 :(得分:2)
在Swift 4中,distanceTo()
已被弃用。您可能需要将String
转换为NSString
才能利用其-[NSString rangeOfString:]
方法,该方法会返回NSRange
。
答案 3 :(得分:1)
Swift 4完整解决方案:
OffsetIndexableCollection(使用Int索引的字符串)
https://github.com/frogcjn/OffsetIndexableCollection-String-Int-Indexable-
let a = "01234"
print(a[0]) // 0
print(a[0...4]) // 01234
print(a[...]) // 01234
print(a[..<2]) // 01
print(a[...2]) // 012
print(a[2...]) // 234
print(a[2...3]) // 23
print(a[2...2]) // 2
if let number = a.index(of: "1") {
print(number) // 1
print(a[number...]) // 1234
}
if let number = a.index(where: { $0 > "1" }) {
print(number) // 2
}
答案 4 :(得分:1)
我不知道哪个版本引入了它,但是在Swift 4.2中,您可以轻松地在两者之间进行转换。
要将Range<String.Index>
转换为NSRange
:
let range = s[s.startIndex..<s.endIndex]
let nsRange = NSRange(range, in: s)
要将NSRange
转换为Range<String.Index>
:
let nsRange = NSMakeRange(0, 4)
let range = Range(nsRange, in: s)
请记住,NSRange
是基于UTF-16的,而Range<String.Index>
是基于Character
的。
因此,您不能只使用计数和位置在两者之间转换!
答案 5 :(得分:0)
您可以使用此功能并在需要转换时调用它
extension String
{
func CnvIdxTooIntFnc(IdxPsgVal: Index) -> Int
{
return startIndex.distanceTo(IdxPsgVal)
}
}