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
How to Run Nstimer in Background Beyond 180Sec in iOS 7
How to Use a Custom Font with Dynamic Text Sizes in iOS7
Check If Uicolor Is Dark or Bright
Ios4: How to Use Video File as an Opengl Texture
Uiapplication.Registerforremotenotifications() Must Be Called from Main Thread Only
How to Set Device (Ui) Orientation Programmatically
Xctest and Asynchronous Testing in Xcode 6
Decode Base64Url to Base64 -- Swift
Can't Pass Data Correctly to Modal Presentation Using Foreach and Coredata in Swiftui
Combine Framework Serialize Async Operations
How to Disable Floating Headers in Uitableview with Uitableviewstyleplain
Analysing Assets.Car File in iOS
Uitableviewcell Buttons with Action
Xcode 10: Unable to Attach Db Error
How to Prevent Keyboard Push Up Webview at iOS App Using Phonegap