NSString和Swift.String上的replaceCharactersInRange之间是否有区别?

时间:2015-07-29 09:03:46

标签: objective-c string swift unicode nsstring

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

一个。明确使用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
}

湾生成Range<String.Int>并在Swift String&#39; s 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得到它?

2 个答案:

答案 0 :(得分:2)

NSRange的{​​p> NSString相当于Range的{​​{1}}(又名String.UTF16.Index)。

正确的方式(没有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"

答案 1 :(得分:0)

是。两种方法之间存在差异,第二种方法更为正确。它还可以正确处理多代码字符:

var str  = "Hello , playground"
let range = NSMakeRange(0, 8)
let swiftRange = advance(str.startIndex, range.location)..<advance(str.startIndex, range.length) // I hate this.
var newString = str.stringByReplacingCharactersInRange(swiftRange, withString: "goodbye")
// => goodbye playground
newString = (str as NSString).stringByReplacingCharactersInRange(range, withString: "goodbye")
// => "goodbye, playground"

我假设这是因为范围计算得更好,而不是因为替换方法有不同的实现。 swiftRange是0..<15