I am trying to change colour for all numbers present in a string in swift
code.Example:
var mystring = \"abc 3423 opqrs 474598 lmno 343543\"
First, we need to find the ranges of number existed in the string. One way is to use regular expression
func findNumberRanges(string: String) -> [NSRange]{
let nsString = string as NSString
let regex = try? NSRegularExpression(pattern: "[0-9]+", options: [])
let matches = regex?.matches(in: string, options: .withoutAnchoringBounds, range: NSMakeRange(0, nsString.length))
return matches?.map{$0.range} ?? []
}
Then we can iterate through ranges of number to add the attribute, in this case to set red color.
func attributedNumberString(string: String, numberAttribute: [String: Any]) -> NSAttributedString{
let ranges = findNumberRanges(string: string)
let attributedString = NSMutableAttributedString(string: string)
for range in ranges{
attributedString.addAttributes(numberAttribute, range: range)
}
return attributedString
}
Here is how it is used:
let redColorAttribute = [ NSForegroundColorAttributeName: UIColor.red]
attributedNumberString(string: "6h40m", numberAttribute: redColorAttribute)
I did something like this for a project, So basically this check whether it's a number and save it's location then by using NSAttributedString, we can easily change the character color like this :-
class ViewController: UIViewController {
@IBOutlet weak var mylabel: UILabel!
let numbers = ["0","1","2","3","4","5","6","7","8","9"]
var mystring = "abc 3423 opqrs 474598 lmno 343543"
override func viewDidLoad() {
super.viewDidLoad()
let myAttributedString = NSMutableAttributedString(string: "\(self.mystring)")
var locations: [Int] = []
let characters = mystring.characters
var i = 0
for letter in characters {
i = i + 1
letter.debugDescription
if numbers.contains(String(letter)) {
locations.append(i)
}
}
for item in locations {
print(item)
let myRange = NSRange(location: item - 1, length: 1)
myAttributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: myRange)
}
self.mylabel.attributedText = myAttributedString
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is a screenShot
I am not much familiar with swift but i have try to make demo in objective c and it's works fine as your requirement if it can help,
NSString *str = @"abc 3423 opqrs 474598 lmno 343543";
NSMutableAttributedString *str1 = [[NSMutableAttributedString alloc]initWithString:@"abc 3423 opqrs 474598 lmno 343543"];
NSArray *arr = [str componentsSeparatedByString:@" "];
for (int i = 0; i < arr.count; i++) {
NSString *temp = [arr objectAtIndex:i];
NSCharacterSet* notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if ([temp rangeOfCharacterFromSet:notDigits].location == NSNotFound)
{
NSDictionary *attrs = @{
NSForegroundColorAttributeName:[UIColor redColor]
};
NSRange range = [str rangeOfString:[arr objectAtIndex:i]];
[str1 addAttributes:attrs range:range];
}
}
UILabel *temp = [[UILabel alloc]initWithFrame:CGRectMake(20, 20, 300, 50)];
[self.view addSubview:temp];
temp.attributedText = str1;
You can use logic and concept and can use in swift as your requirement.
Hope this will help :)
Here's an extension using Swift 5 using Zig's answer as reference:
extension String {
func changeColorForNumbers() -> NSMutableAttributedString {
let red = [NSAttributedString.Key.foregroundColor: UIColor.red]
let myAttributedString = NSMutableAttributedString()
for letter in self.unicodeScalars {
let myLetter : NSAttributedString
if CharacterSet.decimalDigits.contains(letter) {
myLetter = NSAttributedString(string: "\(letter)", attributes: orange)
} else {
myLetter = NSAttributedString(string: "\(letter)")
}
myAttributedString.append(myLetter)
}
return myAttributedString
}
}
I think there's a more efficient way to do this. Instead of finding the locations of the numbers and then creating a range for each of them, just change it on the fly.
let myString = "abc 3423 opqrs 474598 lmno 343543"
let redFont = [NSForegroundColorAttributeName: UIColor.red]
let myAttributedString = NSMutableAttributedString()
for letter in myString.unicodeScalars {
let myLetter : NSAttributedString
if CharacterSet.decimalDigits.contains(letter) {
myLetter = NSAttributedString(string: "\(letter)", attributes: redFont)
} else {
myLetter = NSAttributedString(string: "\(letter)")
}
myAttributedString.append(myLetter)
}
myLabel.attributedText = myAttributedString
In addition to being more efficient, checking membership in the CharacterSet.decimalDigits is localization-friendly if you intend to support that.
NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:"Your Text"];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,5)]; //give range where you want
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(5,6)];//give range where you want
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(11,5)]; //give range where you want
YourLable.attributedText = string;