NSRange to Range

前端 未结 13 1216
失恋的感觉
失恋的感觉 2020-11-22 11:59

How can I convert NSRange to Range in Swift?

I want to use the following UITextFieldDelegate method:

相关标签:
13条回答
  • 2020-11-22 12:21

    In Swift 2.0 assuming func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {:

    var oldString = textfield.text!
    let newRange = oldString.startIndex.advancedBy(range.location)..<oldString.startIndex.advancedBy(range.location + range.length)
    let newString = oldString.stringByReplacingCharactersInRange(newRange, withString: string)
    
    0 讨论(0)
  • 2020-11-22 12:22

    This is similar to Emilie's answer however since you asked specifically how to convert the NSRange to Range<String.Index> you would do something like this:

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    
         let start = advance(textField.text.startIndex, range.location) 
         let end = advance(start, range.length) 
         let swiftRange = Range<String.Index>(start: start, end: end) 
         ...
    
    }
    
    0 讨论(0)
  • 2020-11-22 12:22

    A riff on the great answer by @Emilie, not a replacement/competing answer.
    (Xcode6-Beta5)

    var original    = "                                                                    
    0 讨论(0)
  • 2020-11-22 12:22

    In the accepted answer I find the optionals cumbersome. This works with Swift 3 and seems to have no problem with emojis.

    func textField(_ textField: UITextField, 
          shouldChangeCharactersIn range: NSRange, 
          replacementString string: String) -> Bool {
    
      guard let value = textField.text else {return false} // there may be a reason for returning true in this case but I can't think of it
      // now value is a String, not an optional String
    
      let valueAfterChange = (value as NSString).replacingCharacters(in: range, with: string)
      // valueAfterChange is a String, not an optional String
    
      // now do whatever processing is required
    
      return true  // or false, as required
    }
    
    0 讨论(0)
  • 2020-11-22 12:23

    Here's my best effort. But this cannot check or detect wrong input argument.

    extension String {
        /// :r: Must correctly select proper UTF-16 code-unit range. Wrong range will produce wrong result.
        public func convertRangeFromNSRange(r:NSRange) -> Range<String.Index> {
            let a   =   (self as NSString).substringToIndex(r.location)
            let b   =   (self as NSString).substringWithRange(r)
    
            let n1  =   distance(a.startIndex, a.endIndex)
            let n2  =   distance(b.startIndex, b.endIndex)
    
            let i1  =   advance(startIndex, n1)
            let i2  =   advance(i1, n2)
    
            return  Range<String.Index>(start: i1, end: i2)
        }
    }
    
    let s   =   "                                                                    
    0 讨论(0)
  • 2020-11-22 12:25

    This answer by Martin R seems to be correct because it accounts for Unicode.

    However at the time of the post (Swift 1) his code doesn't compile in Swift 2.0 (Xcode 7), because they removed advance() function. Updated version is below:

    Swift 2

    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

    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

    extension String {
        func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
            return Range(nsRange, in: self)
        }
    }
    
    0 讨论(0)
提交回复
热议问题