如何在文本视图中输入“@”后检测字符串

How to detect a string after the '@' is typed in a textview

我已经研究了很长时间了。我已经阅读了 Get currently typed word in UITextView and Get currently typed word in a UITextView 的文章,我认为我已经非常接近了。我的问题是,在我能够成功检测到“@”符号后,由于某种原因,应该返回的单词没有返回。例如:

    func textViewDidChange(_ textView: UITextView) {
    commentString = commentTextView.text
    commentTextView.setTextTyping(text: commentTextView.text, withHashtagColor: .blue, andMentionColor: .red, andCallBack: callBack, normalFont: UIFont(name: "HelveticaNeue", size: 14)!, hashTagFont: UIFont(name: "HelveticaNeue-Medium", size: 14)!, mentionFont: UIFont(name: "HelveticaNeue-Medium", size: 14)!)
    if let word = textView.currentWord {
        if word.hasPrefix("@")  {
            print(word)
            print(users)
            print("Observing")
        }
    }
}

我能够检测到“@”,但是,在对 .hasPrefix 进行布尔测试之后,应该跟在后面的单词没有被打印到控制台。如果我在布尔测试之前打印 'word' ,那么正确的单词就会打印到控制台。这是我用来检测“@”符号的扩展。

extension UITextView {

    var currentWord : String? {
        let beginning = beginningOfDocument

        if let start = position(from: beginning, offset: selectedRange.location),
            let end = position(from: start, offset: selectedRange.length) {

            let textRange = tokenizer.rangeEnclosingPosition(end, with: .word, inDirection: 1)

            if let textRange = textRange {
                return text(in: textRange)
            }
        }
        return nil
    }
}

提前感谢任何帮助,谢谢!

您可以通过 separating 整个 textview 的文本通过“@”实现它:

let text = "My Text goes here @ the next text"
let separated = text.components(separatedBy: "@")

从而从结果数组中得到最后一个字符串(separated):

if let textAfterAt = separated.last {
    print(textAfterAt) // " the next text"
}

请注意,如果文本包含多个“@”,结果将是最后一个“@”之后的字符串,例如:

let text = "My Text goes here @ the next text @ the last text after the at"
let separated = text.components(separatedBy: "@")
if let textAfterAt = separated.last {
    print(textAfterAt) // " the last text after the at"
}

在这种情况下,我更喜欢使用正则表达式,但它似乎比我记得的要复杂得多。请参阅下面的代码(游乐场代码)

#1
let testString1: NSString = "This is a test of a @single prepended word"
let testString2: NSString = "This is a test of a @two @prepended words"

let regEx = try? NSRegularExpression(pattern: "\@\w+")
let results = regEx?.matches(in: String(testString2), options: [], range: NSMakeRange(0, testString2.length))

for result in results! {
    let word = testString2.substring(with: result.range)
    // #2
    print(word)
}

Output

@two

@prepended

#1 由于最近 Swift 4 对 String 的更改(String 又是字符的集合),我只能使用 NSStrings 实现此目的。

#2 你现在有了字符串中的每个单词和单词的范围,所以你现在可以做一些 work/calculations 并用你想要的任何东西替换每个单词想。

使用委托在键入字符时获取更新。使用正则表达式查找所有以 @ 开头的单词,然后将所需的属性应用于每个匹配并将属性字符串分配回文本字段。

    class ViewController: UIViewController {
        let regex = try! NSRegularExpression(pattern: "\@(\w+)")
        let highlightAttributes = [NSForegroundColorAttributeName : UIColor.blue]
    }

    extension ViewController: UITextFieldDelegate {
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            guard let originalText = textField.text as? NSString else {
                return false
            }
            let proposedText = originalText.replacingCharacters(in: range, with: string)
            let matches = regex.matches(in: proposedText, options: [], range: NSRange(location: 0, length: proposedText.count))
            let attributedText = NSMutableAttributedString(string: proposedText)
            matches.forEach {attributedText.addAttributes(self.highlightAttributes, range: [=10=].range)}
            textField.attributedText = attributedText
            return false
        }
    }

所以您目前还没有完全了解 currentWord 中的内容。看起来您只得到了 @ 字符。 currentWord 是一个变量,看起来您没有正确地遍历文本字段中的所有字符。这就是我的处理方式:

if let splitText = textField.text?.split(separator: " ") {
    for word in splitText {
            if word.hasPrefix("@") {
                print(word) // call whatever function you need here
            } else {
                print("NOPE")
            }
        }
} else {
    print("No Text!!")
}

这只会在找到 @ 并且 word 包含 @@ 之后的每个字符时触发,直到 " " ( space)