Search code examples
iosswiftnsattributedstring

Change color of specific words in String


I'm trying to change the color of specific words which start with a @ however I keep getting an error in the below code.

From what I can see it seem to be something with the range variable.

I get the following error:

cannot invoke 'addAttribute' with an argument list of type (String, value: UIColor, range Range?)

Code:

var messageMutableString = NSMutableAttributedString(string: message, attributes: [NSFontAttributeName:UIFont(name: "PT Sans", size: 13.0)!])

var words = message.componentsSeparatedByString(" ")

for word in words {
    if word.hasPrefix("@") {
        var range = message.rangeOfString(word)
        messageMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor(rgba: "#B52519"), range: range)
    }
}

Solution

  • Rather than split the string into components, I'd use a regular expression search to find the ranges of the strings beginning with @ and then apply the colour. Below is a working example:

    extension String {
    
        public func getMatches(regex: String, options: NSStringCompareOptions?) -> [Range<String.Index>] {
            var arr = [Range<String.Index>]()
            var rang = Range(start: self.startIndex, end: self.endIndex)
            var foundRange:Range<String.Index>?
    
            do
            {
                foundRange = self.rangeOfString(regex, options: options ?? nil, range: rang, locale: nil)
    
                if let a = foundRange {
                    arr.append(a)
                    rang.startIndex = foundRange!.endIndex
                }
            }
                while foundRange != nil
            return  arr
        }
    
    }
    
    
    let message = "hello @you how are @you today?"
    let matches = message.getMatches("@[^ ]{1,}", options: NSStringCompareOptions.RegularExpressionSearch)
    let messageMutableString = NSMutableAttributedString(string: message, attributes: [NSFontAttributeName:UIFont(name: "Helvetica", size: 13.0)!])
    for m in matches {
                messageMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSRange(location:distance(message.startIndex,m.startIndex),length:distance(m.startIndex,m.endIndex)))
    
    }
    messageMutableString // string with added attributes
    

    The range issue is resolved in the following: NSRange(location:distance(message.startIndex,m.startIndex),length:distance(m.startIndex,m.endIndex)). Range and NSRange are not interchangeable, you must fulfil the requirement for one or the other. Using distance() you can retrieve the required Int values to instantiate an NSRange.