在Swift中使用StringByReplacingCharactersRange

在Swift中使用StringByReplacingCharactersRange,swift,Swift,我试图在Swift/Xcode6中使用UITextFieldDelegate,我正在努力使用stringByReplacingCharactersInRange的方式。编译器错误为“无法将表达式的类型“String”转换为类型“$T8” func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool

我试图在Swift/Xcode6中使用UITextFieldDelegate,我正在努力使用stringByReplacingCharactersInRange的方式。编译器错误为“无法将表达式的类型“String”转换为类型“$T8”

func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool
{
    let s = textField.text.stringByReplacingCharactersInRange(range:range, withString:string)
    if countElements(s) > 0 {

    } else {

    }
    return true
}

Xcode 6 Beta 5的更新:问题是shouldChangeCharactersRange提供了一个NSRange对象,我们需要一个Swift Range对象作为StringByReplacingCharactersRange。这仍然可以被认为是一个bug吗?因为我不明白为什么我们仍然要处理NS*对象?委托方法的字符串参数无论如何都是Swift类型。

以下是如何在各种Swift版本中计算结果字符串

请注意,所有方法都以完全相同的方式使用
-[NSString stringByReplacingOccurrencesOfString:withString:][/code>,只是语法不同

这是计算结果字符串的首选方法。转换为Swift
范围并在Swift
字符串上使用该范围容易出错。例如,当对非ASCII字符串进行操作时,Johan的回答在两个方面是不正确的

Swift 3: Swift 2.1: Swift 1(此处仅供参考):
创建String.Index很麻烦

let string = "hello"
let range = string.startIndex .. string.startIndex.succ().succ()
let result = string.stringByReplacingCharactersInRange(range, withString: "si")

我找到的最简单的解决方案是将
用作NSString
——这使我们能够使用
NSRange

var textField : UITextField = UITextField()
textField.text = "this is a test"

let nsRange : NSRange = NSRange(location: 0, length: 4)

let replaced = (textField.text as NSString)
               .stringByReplacingCharactersInRange(nsRange, withString: "that");

NSLog("Replaced: %@", replaced); //prints "that is a test"
这是一个来自的交叉帖子,但是没有办法使Swift原生
字符串成为
范围。StringByRePlacingCharactersRange()
非常无用。因此,这里有一个函数来生成一个
范围

func RangeMake(#开始:Int,#结束:Int)->Range{
断言(开始字符串){
var result=“”
因为我在0…计数{
结果+=str
}
返回结果
}
让长度=结束-开始
让padding=rep(“,start)
设短划线=代表(“-”,长度)
让搜索=填充+破折号
返回search.rangeOfString(破折号,选项:nil,范围:range(开始:search.startIndex,结束:search.endIndex),区域设置:NSLocale.systemLocale())
}
让sourceString=“叫我以实玛利。”
let range=RangeMake(开始:8,结束:15)
让name=sourceString.substringWithRange(范围)
//name=“以实玛利”

我创建了对
NSRange
转换为
范围的扩展

在Swift 2.1中,扩展如下所示:

extension NSRange {
    func toRange(string: String) -> Range<String.Index> {
        let startIndex = string.startIndex.advancedBy(location)
        let endIndex = startIndex.advancedBy(length)
        return startIndex..<endIndex
    }
}
扩展名NSRange{ 函数范围(字符串:字符串)->范围{ 让startIndex=string.startIndex.advancedBy(位置) 让endIndex=startIndex.advancedBy(长度) 返回startIndex。。
bridgeToObjectiveC可以在即将发布的iOS 8.3更新中删除。请使用以下代码

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    if textField.isEqual(<textField whose value to be copied>)
    {
        <TextField to be updated>.text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    }

    return true
}
func textField(textField:UITextField,shouldChangeCharactersRange:NSRange,replacementString:string)->Bool
{
if textField.isEqual()
{
.text=(textField.text作为NSString)。StringByReplacingCharactersRange(范围,带字符串:string)
}
返回真值
}

除了以下几点之外,我什么都没用:(仅供参考,我使用的是Xcode7.0 GMSwift 2.0iOS9GM


在Swift 2.0中,Durul的答案必须更改,因为必须使用characters.count而不是count()

必须做到以下几点

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let length = textField.text!.characters.count - range.length + string.characters.count
    if length > 0 {
        submitButton.enabled = true
    } else {
        submitButton.enabled = false
    }
    return true
}

Swift 4:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    var text = textField.text ?? ""
    text.replaceSubrange(range.toRange(string: text), with: string)
    ...
    return true
}

extension NSRange {

    /// Convert to Range for given string
    ///
    /// - Parameter string: the string
    /// - Returns: range
    func toRange(string: String) -> Range<String.Index> {
        let range = string.index(string.startIndex, offsetBy: self.lowerBound)..<string.index(string.startIndex, offsetBy: self.upperBound)
        return range
    }
}
func textField(textField:UITextField,shouldChangeCharacters范围:NSRange,replacementString:string)->Bool{
var text=textField.text??“”
text.replaceSubrange(range.toRange(string:text),with:string)
...
返回真值
}
扩展NSRange{
///转换为给定字符串的范围
///
///-参数字符串:字符串
///-返回:范围
函数范围(字符串:字符串)->范围{

let range=string.index(string.startIndex,offsetBy:self.lowerBound)工作和测试

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let newString = NSString(string: textField.text!).replacingCharacters(in: range, with: string)

    print(newString)

      return true;
}

在Swift 4中,这有点简单,就像Alexander Volkov的答案一样,但没有扩展

   func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let revisedText: String
        if let text = textField.text, let swiftRange = Range(range, in: text) {
            revisedText = text.replacingCharacters(in: swiftRange, with: string)
        } else {
            revisedText = string
        }
        // Do something with the text and return boolean.
   }

String有这个方法。请看我的评论。@TomášLinhart
String
在哪里声明这个方法?我在Swift模块中找不到它。@NikolaiRuhe我不知道。但是看到我的帖子并在操场上运行,你会看到它的效果。至少在Beta 5中,这不再是正确的答案。请使用“textField.text作为NSString”相反,我会将此作为一个bug发布。应该有更好的方法来创建字符串范围。或者可能我就是找不到。请随意报告。我也没有找到更好的方法。我同意,我的直觉是这是一个bug。例如stringByAppendingString按预期工作。肯定是最快捷的答案。但你可以避免
self
s:)@DavideDeFranceschi为了清晰起见,我添加了
self
s。但是你是对的,它们不是必需的。这是一个很好的方法,但是当你使用unicode字符,例如表情符号时,它会中断。试一下在Swift 2中,你会使用
advancedBy
让startIndex=string.startIndex.advancedBy(位置);让endIndex=startIndex.advancedBy(length)
结束索引不应该按
location+length
?短而甜。从swift2开始,textField.text需要强制展开:让newString=(textField.text!作为NSString)。stringByReplacingCharactersInRange(range,withString:string)当我删除一个字符时,我得到一个
致命错误:无法前进超过endIndex
@Maximelc建议的方法是正确的。请提供您的代码。
extension NSRange {
    func toRange(string: String) -> Range<String.Index> {
        let startIndex = string.startIndex.advancedBy(location)
        let endIndex = startIndex.advancedBy(length)
        return startIndex..<endIndex
    }
}
let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    if textField.isEqual(<textField whose value to be copied>)
    {
        <TextField to be updated>.text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    }

    return true
}
import UIKit

class LoginViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var submitButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }



    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        let length = count(textField.text) - range.length + count(string)
        if length > 0 {
            submitButton.enabled = true
        } else {
            submitButton.enabled = false
        }
        return true
    }
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let currentText = textField.text ?? ""
    let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)
    print("prospectiveText", prospectiveText)
    return true;
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let length = textField.text!.characters.count - range.length + string.characters.count
    if length > 0 {
        submitButton.enabled = true
    } else {
        submitButton.enabled = false
    }
    return true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    var text = textField.text ?? ""
    text.replaceSubrange(range.toRange(string: text), with: string)
    ...
    return true
}

extension NSRange {

    /// Convert to Range for given string
    ///
    /// - Parameter string: the string
    /// - Returns: range
    func toRange(string: String) -> Range<String.Index> {
        let range = string.index(string.startIndex, offsetBy: self.lowerBound)..<string.index(string.startIndex, offsetBy: self.upperBound)
        return range
    }
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let newString = NSString(string: textField.text!).replacingCharacters(in: range, with: string)

    print(newString)

      return true;
}
   func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let revisedText: String
        if let text = textField.text, let swiftRange = Range(range, in: text) {
            revisedText = text.replacingCharacters(in: swiftRange, with: string)
        } else {
            revisedText = string
        }
        // Do something with the text and return boolean.
   }