Color All Occurrences of String in Swift

Color all occurrences of string in swift

Swift 5

let attrStr = NSMutableAttributedString(string: "hi hihi hey")
let inputLength = attrStr.string.count
let searchString = "hi"
let searchLength = searchString.characters.count
var range = NSRange(location: 0, length: attrStr.length)

while (range.location != NSNotFound) {
range = (attrStr.string as NSString).range(of: searchString, options: [], range: range)
if (range.location != NSNotFound) {
attrStr.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.yellow, range: NSRange(location: range.location, length: searchLength))
range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
}
}

Swift 3

let attrStr = NSMutableAttributedString(string: "hi hihi hey")
let inputLength = attrStr.string.characters.count
let searchString = "hi"
let searchLength = searchString.characters.count
var range = NSRange(location: 0, length: attrStr.length)

while (range.location != NSNotFound) {
range = (attrStr.string as NSString).range(of: searchString, options: [], range: range)
if (range.location != NSNotFound) {
attrStr.addAttribute(NSForegroundColorAttributeName, value: UIColor.yellow(), range: NSRange(location: range.location, length: searchLength))
range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
}
}

Swift 2

let attrStr = NSMutableAttributedString(string: "hi hihi hey")
let inputLength = attrStr.string.characters.count
let searchString = "hi"
let searchLength = searchString.characters.count
var range = NSRange(location: 0, length: attrStr.length)

while (range.location != NSNotFound) {
range = (attrStr.string as NSString).rangeOfString(searchString, options: [], range: range)
if (range.location != NSNotFound) {
attrStr.addAttribute(NSForegroundColorAttributeName, value: UIColor.yellowColor(), range: NSRange(location: range.location, length: searchLength))
range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
}
}

Color a string based on occurrences in a Variable String

The way you are going about it is quite complicated. I'd use enumerateSubstrings to get each word in the string. And then instead of passing in a comma-separated string with search terms I'd pass in an array of search strings.

extension String {
func highlighted(
redText: [String],
yellowText: [String],
greenText: [String]
) -> NSAttributedString {

let result = NSMutableAttributedString(string: self)
enumerateSubstrings(in: startIndex..<endIndex, options: .byWords) {
(substring, substringRange, _, _) in
guard let substring = substring else { return }
if redText.contains(substring) {
result.addAttribute(
.foregroundColor,
value: UIColor.systemRed,
range: NSRange(substringRange, in: self)
)
}
if yellowText.contains(substring) {
result.addAttribute(
.foregroundColor,
value: UIColor.systemYellow,
range: NSRange(substringRange, in: self)
)
}
if greenText.contains(substring) {
result.addAttribute(
.foregroundColor,
value: UIColor.systemGreen,
range: NSRange(substringRange, in: self)
)
}
}
return result
}
}

The usage is as follows:

let highlighted = "TEST TO COLOUR IT WORDS EXIST".highlighted(
redText: ["TO", "POT", "TEST"],
yellowText: ["EXIST", "TOP"],
greenText: ["AB", "+TA", "-XY", "WORDS"]
)

Color Part of String

For this example, I have a timer which fires every second, and then build up a string with an incrementing counter variable in the middle of the displayed string - does this match what you need?

class ViewController: UIViewController {

@IBOutlet weak var lblDisplay: UILabel!
var timer : Timer!
var timerLoop : Int = 0


override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
}

@objc func timerFired()
{
timerLoop += 1

let main_string = "First part \(timerLoop) second part"
let string_to_color = "\(timerLoop)" //stringTime is a string of a number, for example "21"


let range = (main_string as NSString).range(of: string_to_color)

let attribute = NSMutableAttributedString.init(string: main_string)
attribute.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red , range: range)

self.lblDisplay.attributedText = attribute
}

}

How to change color of type Character (not String) in a UILabel?

You should use textLabel.attributedText instead of textLabel.text

To see how NSAttributedText works: read the documentation of NSAttributedText or this stack overflow answer

So a possible solution is to iterate over all the characters in your string and to a add red foreground color if the character is "3"

Swift 3:

textLabel.attributedText = "3ab apple3 3bana".characters.reduce(NSMutableAttributedString()) {
$0.append(
NSAttributedString(
string: String($1),
attributes: [
NSForegroundColorAttributeName: $1 == "3" ? UIColor.red : .black
]
)
)
return $0
}

Swift 4:

textLabel.attributedText = "3ab apple3 3bana".reduce(NSMutableAttributedString()) {
$0.append(
NSAttributedString(
string: String($1),
attributes: [
.foregroundColor: $1 == "3" ? UIColor.red : .black
]
)
)
return $0
}

Not a duplicate

I think this is not a duplicate of Color all occurrences of string in swift because Strings and Characters are two different things in Swift!

Swift 4 array issue in changing text colour


let main_string = "By continuing you agree to our Term of use and Privacy Policy "

var string_to_color = ["By continuing you agree to our","and"]

for i in 0..<2
{

let range = (main_string as NSString).range(of: string_to_color[i])

let attributedString = NSMutableAttributedString.init(string:main_string)

attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.black , range: range)

privacyL.attributedText = attributedString

}

You are overriding each time privacyL.attributedText, so you'll get only the "result" of last iteration.

Instead, do:

let attributedString = NSMutableAttributedString.init(string:main_string)
for i in 0..<2
{
let range = (main_string as NSString).range(of: string_to_color[i])
attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.black , range: range)

}
privacyL.attributedText = attributedString

Now, next issues:
Don't do a loop for i in 0..<2, instead use at least the count of string_to_color (or a for each loop). If tomorrow you add a string in it or remove one, you'll encounter an issue.

Also range(of:) will return the first occurence found, so if you have:

let main_string = "and and"
var string_to_color = ["something", "and"]

only the first "and" will be colored.

You have then to iterate or use a NSRegularExpression.
Here is a related question: Color all occurrences of string in swift



Related Topics



Leave a reply



Submit