首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >NSRange到Range<String.Index>

NSRange到Range<String.Index>
EN

Stack Overflow用户
提问于 2014-08-05 12:01:21
回答 16查看 137.3K关注 0票数 284

如何在Swift中将NSRange转换为Range<String.Index>

我想使用以下UITextFieldDelegate方法:

代码语言:javascript
运行
复制
    func textField(textField: UITextField!,
        shouldChangeCharactersInRange range: NSRange,
        replacementString string: String!) -> Bool {

textField.text.stringByReplacingCharactersInRange(???, withString: string)

EN

回答 16

Stack Overflow用户

回答已采纳

发布于 2014-10-22 21:46:14

StringNSString版本(相对于Swift字符串)接受NSRange,因此一个简单的解决方案是将转换为 NSString first。在Swift 3和2中,委托和替换方法名称略有不同,因此取决于您使用的Swift:

Swift 3.0

代码语言:javascript
运行
复制
func textField(_ textField: UITextField,
               shouldChangeCharactersIn range: NSRange,
               replacementString string: String) -> Bool {

  let nsString = textField.text as NSString?
  let newString = nsString?.replacingCharacters(in: range, with: string)
}

Swift 2.x

代码语言:javascript
运行
复制
func textField(textField: UITextField,
               shouldChangeCharactersInRange range: NSRange,
               replacementString string: String) -> Bool {

    let nsString = textField.text as NSString?
    let newString = nsString?.stringByReplacingCharactersInRange(range, withString: string)
}
票数 273
EN

Stack Overflow用户

发布于 2015-05-22 19:29:09

Swift 4 (Xcode 9)中,Swift标准库提供了在Swift字符串范围(Range<String.Index>)和NSString范围(NSRange)之间进行转换的方法。示例:

代码语言:javascript
运行
复制
let str = "abc"
let r1 = str.range(of: "")!

// String range to NSRange:
let n1 = NSRange(r1, in: str)
print((str as NSString).substring(with: n1)) // 

// NSRange back to String range:
let r2 = Range(n1, in: str)!
print(str[r2]) // 

因此,文本字段委托方法中的文本替换现在可以作为

代码语言:javascript
运行
复制
func textField(_ textField: UITextField,
               shouldChangeCharactersIn range: NSRange,
               replacementString string: String) -> Bool {

    if let oldString = textField.text {
        let newString = oldString.replacingCharacters(in: Range(range, in: oldString)!,
                                                      with: string)
        // ...
    }
    // ...
}

( Swift 3及更早版本的旧答案:)

在SWIFT1.2中,String.Index有一个初始化器

代码语言:javascript
运行
复制
init?(_ utf16Index: UTF16Index, within characters: String)

可用于正确地将NSRange转换为Range<String.Index> (包括所有表情符号、区域指示符或其他扩展的图形素集群),而无需中间转换为NSString

代码语言:javascript
运行
复制
extension String {
    func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
        let from16 = advance(utf16.startIndex, nsRange.location, utf16.endIndex)
        let to16 = advance(from16, nsRange.length, utf16.endIndex)
        if let from = String.Index(from16, within: self),
            let to = String.Index(to16, within: self) {
                return from ..< to
        }
        return nil
    }
}

此方法返回一个可选字符串范围,因为并非所有的NSRange都对给定的Swift字符串有效。

然后,可以将UITextFieldDelegate委托方法编写为

代码语言:javascript
运行
复制
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    if let swRange = textField.text.rangeFromNSRange(range) {
        let newString = textField.text.stringByReplacingCharactersInRange(swRange, withString: string)
        // ...
    }
    return true
}

逆变换是

代码语言:javascript
运行
复制
extension String {
    func NSRangeFromRange(range : Range<String.Index>) -> NSRange {
        let utf16view = self.utf16
        let from = String.UTF16View.Index(range.startIndex, within: utf16view) 
        let to = String.UTF16View.Index(range.endIndex, within: utf16view)
        return NSMakeRange(from - utf16view.startIndex, to - from)
    }
}

一个简单的测试:

代码语言:javascript
运行
复制
let str = "abc"
let r1 = str.rangeOfString("")!

// String range to NSRange:
let n1 = str.NSRangeFromRange(r1)
println((str as NSString).substringWithRange(n1)) // 

// NSRange back to String range:
let r2 = str.rangeFromNSRange(n1)!
println(str.substringWithRange(r2)) // 

Swift 2的更新:

Swift 2版本的rangeFromNSRange()已经由Serhii在this answer中提供,为了完整起见,我在这里包括它:

代码语言:javascript
运行
复制
extension String {
    func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
        let from16 = utf16.startIndex.advancedBy(nsRange.location, limit: utf16.endIndex)
        let to16 = from16.advancedBy(nsRange.length, limit: utf16.endIndex)
        if let from = String.Index(from16, within: self),
            let to = String.Index(to16, within: self) {
                return from ..< to
        }
        return nil
    }
}

Swift 2版本的NSRangeFromRange()

代码语言:javascript
运行
复制
extension String {
    func NSRangeFromRange(range : Range<String.Index>) -> NSRange {
        let utf16view = self.utf16
        let from = String.UTF16View.Index(range.startIndex, within: utf16view)
        let to = String.UTF16View.Index(range.endIndex, within: utf16view)
        return NSMakeRange(utf16view.startIndex.distanceTo(from), from.distanceTo(to))
    }
}

Swift 3的更新(Xcode 8):

代码语言:javascript
运行
复制
extension String {
    func nsRange(from range: Range<String.Index>) -> NSRange {
        let from = range.lowerBound.samePosition(in: utf16)
        let to = range.upperBound.samePosition(in: utf16)
        return NSRange(location: utf16.distance(from: utf16.startIndex, to: from),
                       length: utf16.distance(from: from, to: to))
    }
}

extension String {
    func range(from nsRange: NSRange) -> Range<String.Index>? {
        guard
            let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
            let to16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location + nsRange.length, limitedBy: utf16.endIndex),
            let from = from16.samePosition(in: self),
            let to = to16.samePosition(in: self)
            else { return nil }
        return from ..< to
    }
}

示例:

代码语言:javascript
运行
复制
let str = "abc"
let r1 = str.range(of: "")!

// String range to NSRange:
let n1 = str.nsRange(from: r1)
print((str as NSString).substring(with: n1)) // 

// NSRange back to String range:
let r2 = str.range(from: n1)!
print(str.substring(with: r2)) // 
票数 403
EN

Stack Overflow用户

发布于 2015-09-03 15:18:20

Martin的This answer似乎是正确的,因为它解释了Unicode。

然而,在发布文章(Swift 1)时,他的代码没有在SWIFT2.0 (Xcode 7)中编译,因为它们删除了advance()函数。最新版本如下:

Swift 2

代码语言:javascript
运行
复制
extension String {
    func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
        let from16 = utf16.startIndex.advancedBy(nsRange.location, limit: utf16.endIndex)
        let to16 = from16.advancedBy(nsRange.length, limit: utf16.endIndex)
        if let from = String.Index(from16, within: self),
            let to = String.Index(to16, within: self) {
                return from ..< to
        }
        return nil
    }
}

Swift 3

代码语言:javascript
运行
复制
extension String {
    func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
        if let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
            let to16 = utf16.index(from16, offsetBy: nsRange.length, limitedBy: utf16.endIndex),
            let from = String.Index(from16, within: self),
            let to = String.Index(to16, within: self) {
                return from ..< to
        }
        return nil
    }
}

Swift 4

代码语言:javascript
运行
复制
extension String {
    func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
        return Range(nsRange, in: self)
    }
}
票数 22
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25138339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档