2

I found this question: How to make UITextView detect hashtags? and I copied the accepted answer into my code. I also set up a delegate to my textview and then put this code:

func textViewDidChange(textView: UITextView) { 
    textView.resolveHashTags()
}

By doing that I want to check the user's input on the textview and each time user types a #hashtag - I will automatically highlight it.

But there is a weird problem: it never highlights words that starts with the same letters.

It looks like this:

enter image description here

what might be the problem here?

Community
  • 1
  • 1
user3766930
  • 5,629
  • 10
  • 51
  • 104
  • You might like to look at https://github.com/optonaut/ActiveLabel.swift I used this in a recent project and it worked really well. – OrderAndChaos Sep 18 '16 at 09:18
  • @Sarcoma thanks, but it does not apply to the input text view, so that's the reason I'm not using that... – user3766930 Sep 18 '16 at 09:24
  • I see what you want to do now, I actually wrote a script to do that last week, but with @name mentions. I don't have it on me though. – OrderAndChaos Sep 18 '16 at 09:29
  • I used a method similar to this: http://stackoverflow.com/questions/31129527/how-do-i-get-the-last-n-characters-typed-in-a-uitextview/39454023#39454023 checking a range of characters for the @ sign, holding that position until a space or the cursor moved, and checking all characters between there and the cursor. If no one has answered this by the time I'm back at work I'll post my solution. – OrderAndChaos Sep 18 '16 at 09:31
  • @Sarcoma thanks man, I will really appreciate that! – user3766930 Sep 18 '16 at 09:32
  • It was literally building from the answer I posted in the link, feel free to poke around with that, see if you can get somewhere. – OrderAndChaos Sep 18 '16 at 09:34

3 Answers3

2
func resolveHashTags(text : String) -> NSAttributedString{
    var length : Int = 0
    let text:String = text
    let words:[String] = text.separate(withChar: " ")
    let hashtagWords = words.flatMap({$0.separate(withChar: "#")})
    let attrs = [NSFontAttributeName : UIFont.systemFont(ofSize: 17.0)]
    let attrString = NSMutableAttributedString(string: text, attributes:attrs)
    for word in hashtagWords {
        if word.hasPrefix("#") {
                let matchRange:NSRange = NSMakeRange(length, word.characters.count)
                let stringifiedWord:String = word

                attrString.addAttribute(NSLinkAttributeName, value: "hash:\(stringifiedWord)", range: matchRange)
        }
        length += word.characters.count
    }
    return attrString
}

To separate words I used a string Extension

extension String {
    public func separate(withChar char : String) -> [String]{
    var word : String = ""
    var words : [String] = [String]()
    for chararacter in self.characters {
        if String(chararacter) == char && word != "" {
            words.append(word)
            word = char
        }else {
            word += String(chararacter)
        }
    }
    words.append(word)
    return words
}

}

I hope this is what you are looking for. Tell me if it worked out for you.

Edit :

   func textViewDidChange(_ textView: UITextView) {
        textView.attributedText = resolveHashTags(text: textView.text)
        textView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.red]
    }

Edit 2: Updated for swift 3.

unniverzal
  • 803
  • 10
  • 17
0

Little late to the party

    private func getHashTags(from caption: String) -> [String] {
    var words: [String] = []
    let texts = caption.components(separatedBy: " ")
    for text in texts.filter({ $0.hasPrefix("#") }) {
        if text.count > 1 {
            let subString = String(text.suffix(text.count - 1))
            words.append(subString)
        }
    }
    return words
}
Shree Ranga Raju
  • 591
  • 5
  • 11
0

Here is Swift 5 solution as String extension:

extension String
{
    func withHashTags(color: UIColor) -> NSMutableAttributedString
    {
        let words = self.components(separatedBy: " ")
        
        let attributedString = NSMutableAttributedString(string: self)
        
        for word in words
        {
            if word.hasPrefix("#")
            {
                let range = (self as NSString).range(of: word)
                attributedString.addAttribute(.foregroundColor, value: color, range: range)
            }
        }
        
        return attributedString
    }
}

Pass param color to set specific color for hashtags

Vladislav Kovalyov
  • 763
  • 10
  • 24