objective-c - NSString 和 Swift.String 上的 ReplaceCharactersInRange 之间有区别吗

标签 objective-c string swift unicode nsstring

我正在为 UITextField 编写一个验证器,我得到了一个现有字符串、替换字符串和一个发生替换的 NSRange。我有两个版本的代码来获取新的候选字符串:

a.明确使用NSString

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let existingString: NSString = textField.text ?? ""
    let candidateString =  existingString.stringByReplacingCharactersInRange(range, withString: string)
    //do validation on candidateString here
    return true
}

b.生成Range<String.Int>并在 Swift String 的 stringByReplacingCharactersInRange 上使用它

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let existingString = textField.text ?? ""
    let swiftRange = advance(existingString.startIndex, range.length)..<advance(existingString.startIndex, range.length) // I hate this.
    let candidateString = existingString.stringByReplacingCharactersInRange(swiftRange, withString: string)

所以抛开生成 Swift 范围的代码不可读这一事实......这两种方法在执行上是否有所不同?具体来说,Swift 有更好的(可能更懂 unicode)版本的 stringByReplacingCharactersInRange我通过避免转换为 NSString 得到了什么?

最佳答案

NSString

NSRange 相当于 String.UTF16.IndexRange(又名 String .UTF16Index)。

正确的方法(没有NSString)是:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let existingString = textField.text ?? ""

    // convert `NSRange` to `Range<String.Index>`
    let start = String.UTF16Index(range.location)
    let end = start.advancedBy(range.length)
    let swiftRange = start.samePositionIn(string)! ..< end.samePositionIn(string)!

    let candidateString = existingString.stringByReplacingCharactersInRange(swiftRange, withString: string)

    // Do validation...

    return true
}

您可以扩展NSRange:

extension NSRange {
    func toStringRangeIn(string: String) -> Range<String.Index>? {
        let start = String.UTF16Index(self.location)
        let end = start.advancedBy(self.length)
        if let start = start.samePositionIn(string), end = end.samePositionIn(string) {
            return start ..< end
        }
        return nil
    }
}

var str  = "📅Hello 🇬🇧😀"
let range = NSMakeRange(8, 4)
str.stringByReplacingCharactersInRange(range.toStringRangeIn(str)!, withString: "FOO") // -> "📅Hello FOO😀"
(str as NSString).stringByReplacingCharactersInRange(range, withString: "FOO")  // -> "📅Hello FOO😀"

有了这个,您可以:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let existingString = textField.text ?? ""
    let candidateString = existingString.stringByReplacingCharactersInRange(
        range.toStringRangeIn(existingString)!,
        withString: string
    )

    // Do validation...

    return true
}

关于objective-c - NSString 和 Swift.String 上的 ReplaceCharactersInRange 之间有区别吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31695892/

相关文章:

ios - UIViewController presentViewController :animated:completion - taking 4 to 6 seconds to launch

ios - 发现多个名为 'tag' 的方法具有不匹配的结果、参数类型或属性

ios - Objective-C 更改 Sprite 表 - 麻雀

objective-c - 这是传递 ManagedObjectContext 的可接受方式吗?

从c中的结构数组创建一个字符串

swift - 如何在 Swift 中正确支持 CGFloat 数学中的 Int 值?

ios - 用户界面 ImageView : add tap event from Interface Builder

javascript - 如何取消转义从 Android 上的 Javascript 返回的字符串?

python - 将字符串(左右)修剪到最近的单词或句子

swift - 委托(delegate)在 swift 中传递 nil