How to change background only to some words in a textView - objective-c

I need to change the background color of some particular words in a text that stay in a textView. Something similar to what happens in Firefox when you seearch for a word... So lets say I have a textView with this text
"A man is sitting in front of my porch and another man is calling him"
and I want to change background color to the 2 occurence of the word
"man"
... how could I do that?
I know that there is NSAttributedString to do this kind of things but I can not understand how to modify only some particular words... in the examples I found Googling it there were only examples of how to change the first 5 characters or things like this...

Try this:
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString: #"Your String"];
NSUInteger count = 0;
NSUInteger length = [attrString length];
NSRange range = NSMakeRange(0, length);
while(range.location != NSNotFound)
{
range = [[attrString string] rangeOfString:#"YOURWORD" options:0 range:range];
if(range.location != NSNotFound) {
[attrString addAttribute:NSBackgroundColorAttributeName value:YOURCOLOR range:NSMakeRange(range.location, [word length])];
range = NSMakeRange(range.location + range.length, length - (range.location + range.length));
count++;
}
}

Related

How to highlight UILabel formatted phone number while searching [duplicate]

This question already has an answer here:
How to search(Predicate) content from list like Xcode suggestion?
(1 answer)
Closed 4 years ago.
How to highlight UILabel with formatted phone number while searching?
Example:
A cell is displaying a list of contacts with a number like: +381 60 0000000
If I type 3, I want + and 3 to be highlighted (colored differently)
If I type 38160, I want +381 60 to be highlighted (colored differently).
And so on...
The main point of this question is how to color the matching numbers by jumping over white spaces and + sign?
Here is what I've tried so far, but it works only if I remove white spaces and + sign from the label's text value:
// Highlighted search for numbers
NSString *phoneString = #"+381 60 0000000";
NSString *searchString = #"38160";
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:phoneString];
NSRange selectedRange = [[string string] rangeOfString:searchString options:NSRegularExpressionSearch];
if (selectedRange.location != NSNotFound) {
[string beginEditing];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:selectedRange];
[string endEditing];
}
cell.phoneNumberLabel.attributedText = string;
Thanks to #Larme, I have answered my own question :)
// Highlighted search for numbers
NSString *phoneString = #"+381 60 000343";
NSString *firstComponent = #"\\+?"; // Skip a leading + char
NSMutableArray *digits = [[NSMutableArray alloc] init];
[self.searchString enumerateSubstringsInRange:NSMakeRange(0, [self.searchString length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
[digits addObject:substring];
}];
NSString *pattern = [[NSString alloc] initWithFormat:#"%#%#", firstComponent, [digits componentsJoinedByString:#"\\s?"]];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:phoneString];
NSRange selectedRange = [[string string] rangeOfString:pattern options:NSRegularExpressionSearch];
if (selectedRange.location != NSNotFound) {
[string beginEditing];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:selectedRange];
[string endEditing];
}
cell.phoneNumberLabel.attributedText = string;

Count and change text color of occurrences of string in NSTextView

I have an task where I need to count the occurrences of errors in a log file and I know how to do that. Now Im trying to change the font color of these occurrences. I have it kinda working but it doesn't change the whole word to the wanted color and for the next occurrence of that string it shifts over 3 characters.
See image below.
I searched for the word "Checked" and it gave me these results.
Below is the code that I am using
NSArray * lines = [words componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
wordresult = [lines componentsJoinedByString:#""];
if (occS2 == 1)
{
NSString * box2 = [_occSearchTwoTextBox stringValue];
NSUInteger countFatal = 0, length4 = [wordresult length];
NSRange range4 = NSMakeRange(0, length4);
while(range4.location != NSNotFound)
{
range4 = [wordresult rangeOfString: box2 options:NSCaseInsensitiveSearch range:range4];
[self.stringLogTextView setTextColor:[NSColor redColor] range:range4];
NSLog(#"Occurance Edited");
if(range4.location != NSNotFound)
{
range4 = NSMakeRange(range4.location + range4.length, length4 - (range4.location + range4.length));
countFatal++;
}
}
NSString * FatalCount = [NSString stringWithFormat:#"%lu", (unsigned long)countFatal];
[_customSearchTwoTextBox setStringValue:FatalCount];
}
Can anyone please point me to where to why its shifting? I can only assume that it has something to do with my range but I'm not sure what to do to resolve.
Thanks for everyones time!
I'm not sure why your method isn't working correctly, but I would do it a different way. Using enumerateSubstringsInRange:options:usingBlock:, you can enumerate your string by word, and get the range of each word passed in to the method for you. If the word is "Checked", you can increment your count and also set the attributes for that range of a mutable attributed string. Here is an example of how to use that method,
NSString *theText = #"] Tables initialized\n]Database version Checked\n]Got login id-1\n] Tables initialized\n]Database version Checked\n]Got login id-1\n] Tables initialized\n]Database version Checked\n]Got login id-1\n";
NSMutableAttributedString *attrib = [[NSMutableAttributedString alloc] initWithString:theText];
NSDictionary *dict = #{NSForegroundColorAttributeName:[NSColor greenColor]};
__block int count = 0;
[theText enumerateSubstringsInRange:NSMakeRange(0, theText.length) options:NSStringEnumerationByWords usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
if ([substring isEqualToString:#"Checked"]) {
[attrib setAttributes:dict range:substringRange];
count ++;
};
}];
self.textView.textStorage.attributedString = attrib;
NSLog(#"count is: %d",count);

Custom NSFormatter in Objective C

I am trying to write my own custom formatter in Objective C by subclassing NSNumberFormatter. Specifically what I'd like to do is make a number turn red if it is above or below certain values. The apple documentation says
For example, if you want negative financial amounts to appear in red, you have this method return a string with an attribute of red text. In attributedStringForObjectValue:withDefaultAttributes: get the non-attributed string by invoking stringForObjectValue: and then apply the proper attributes to that string.
Based on this advice I implemented the following code
- (NSAttributedString*) attributedStringForObjectValue: (id)anObject withDefaultAttributes: (NSDictionary*)attr;
{
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:[self stringForObjectValue:anObject]];
if ([[attrString string] floatValue] < -20.0f) {
[attrString addAttribute:#"NSForegroundColorAttributeName" value:[NSColor redColor] range:NSMakeRange(0, 10)];
return attrString;
} else return attrString;
}
But when I test this all it does is freeze my application. Any advice would be appreciated. Thanks.
I believe this has something to do with your NSRange that you create. I believe your length (10 in your example) is out of bounds. Try getting the length of the string that you use to initialize your NSMutableAttributedString.
For example:
- (NSAttributedString*) attributedStringForObjectValue: (id)anObject withDefaultAttributes: (NSDictionary*)attr;
{
NSString *string = [self stringForObjectValue:anObject];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:string];
NSInteger stringLength = [string length];
if ([[attrString string] floatValue] < -20.0f)
{
[attrString addAttribute:#"NSForegroundColorAttributeName" value:[NSColor redColor] range:NSMakeRange(0, stringLength)];
}
return attrString;
}
Here is how I was finally able to implement this. To make it more visible when a number is negative, I decided to make the background of the text red with white text. The following code does work in a NSTextField cell. I'm not sure why the code in my question (and the answer) does not work, addAttribute should work.
- (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes: (NSDictionary *)attributes{
NSString *string = [self stringForObjectValue:anObject];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:string];
NSInteger stringLength = [string length];
if ([[attrString string] floatValue] < 0)
{
NSDictionary *firstAttributes = #{NSForegroundColorAttributeName: [NSColor whiteColor],
NSBackgroundColorAttributeName: [NSColor blueColor]};
[attrString setAttributes:firstAttributes range:NSMakeRange(0, stringLength)];
}
return attrString;
}

How to make text bigger in label?

I am wanting to use NSMutableAttributedString to change part of the original string and make part of the text bigger then the original. However, it is not working because of something very minor that I can't figure out. Here is my code:
NSString *combineString = [NSString stringWithFormat:#"%#", ...];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:combineString];
NSRange selectedRange = NSMakeRange(5, 4); // 4 characters, starting at index 22
[string beginEditing];
[string addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:50]
range:selectedRange];
[string endEditing];
mainCell.label.text = combineString;
You’re setting the text property, which takes an NSString—your attributed string, string, isn’t actually going anywhere. Try this:
mainCell.label.attributedText = string;

NSMutableAttributedStrings - objectAtIndex:effectiveRange:: Out of bounds

I'm trying to add some fancy text to a label, but I've run into some problems with the NSMutableAttributedString class. I was trying to achieve four this: 1. Change font, 2. Underline range, 3. Change range color, 4. Superscript range.
This code:
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
NSMutableAttributedString* display = [[NSMutableAttributedString alloc]
initWithString:#"Hello world!"];
NSUInteger length = [[display string]length] - 1;
NSRange wholeRange = NSMakeRange(0, length);
NSRange helloRange = NSMakeRange(0, 4);
NSRange worldRange = NSMakeRange(6, length);
NSFont* monoSpaced = [NSFont fontWithName:#"Menlo"
size:22.0];
[display addAttribute:NSFontAttributeName
value:monoSpaced
range:wholeRange];
[display addAttribute:NSUnderlineStyleAttributeName
value:[NSNumber numberWithInt:1]
range:helloRange];
[display addAttribute:NSForegroundColorAttributeName
value:[NSColor greenColor]
range:helloRange];
[display addAttribute:NSSuperscriptAttributeName
value:[NSNumber numberWithInt:1]
range:worldRange];
//#synthesize textLabel; is in this file.
[textLabel setAttributedStringValue:display];
}
Gives me this error:
NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds
Also, I tried messing around with the ranges, but became even more confused when I tried NSRange worldRange = NSMakeRange(4, 5);. I don't understand why that produces this: Hell^o wor^ld!, where the letters inside the ^s are superscripts.
NSRange worldRange = NSMakeRange(6, 6); produces the desired effect, hello ^world!^.
What the label looks like:
Your length is too long on worldRange. NSMakeRange takes two arguments, the start point and the length, not the start point and the end point. That's probably why you are getting confused about both problems.
NSRange has two values, the start index and the length of the range.
So if you're starting at index 6 and going length characters after that you're going past the end of the string, what you want is:
NSRange worldRange = NSMakeRange(6, length - 6);