How to find and apply two fonts in a label in IOS - ios

I know to apply two fonts in a label for single word with one font and rest with another font using below code..
int lengthofname#"Anand";
UIFont *boldFont = [UIFont fontWithName:#"BodoniStd" size:15];
UIFont *regularFont = [UIFont fontWithName:#"BodoniStd-BoldItalic" size:15];
//UIColor *foregroundColor = [UIColor clearColor];
// Create the attributes
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
boldFont, NSFontAttributeName,nil];
//NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
// boldFont, NSFontAttributeName,
// foregroundColor, NSForegroundColorAttributeName, nil];
NSDictionary *subAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
regularFont, NSFontAttributeName, nil];
const NSRange range = NSMakeRange(0,lengthofname);
// range of " 2012/10/14 ". Ideally this should not be hardcoded const
// Create the attributed string (text + attributes)
NSMutableAttributedString *attributedText =
[[NSMutableAttributedString alloc] initWithString:#"Anand is good programmer"
attributes:attrs];
[attributedText setAttributes:subAttrs range:range];
// Set it in our UILabel and we are done!
[self.descLabel setAttributedText:attributedText];
My requirement is to find some x words in a label and then apply Bold font and rest of text with Regular font..
Please suggest any ideas. Thanks in Advance..!

In this example there highlighted words are not funded with regular expression but I believe there is some list (NSArray: STANDARD, EXPRESS, NEXT DAY, etc) of keywords. And what you have to do is enumerate that array to find the rang in text and if founded apply the different font style, something like that:
for (NSString * keyword in listOfKeywordArray) {
NSRange range = [longTextString rangeOfString:#"keyword"];
if (range.location != NSNotFound) {
//Keyword found, apply different font
// This of course needs to be changed to apply font you want
[attrString addAttribute:NSFontAttributeName value:fontName range:range];
}
}

Greg's answer is pretty close. If you have an array of keywords, you can use for.. in to loop through the array of keywords. Then you'd need to use an inner loop with rangeOfString:options:range to find all occurrences of a given keyword.
That method returns an NSRange. You could use setAttributes:range: on the range to set the text attributes of each occurrence of each keyword to use the font and style you want. (Greg's code using addAttribute only lets you set a single attribute on the text. setAttributes:range: and addAttributes:range: both let you specify a whole dictionary of attributes, like in the code you posted. Your code might look like this:
//Whatever font attributes you want to use
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
boldFont, NSFontAttributeName,nil];
NSArray *keywords = [#"STANDARD", #"EXPRESS", #"NEXT DAY"];
//Loop through each keyword in the array of keywords.
for (NSString aKeyword in keywords)
{
//Set the range to the whole string to start with.
NSRange range = NSMakeRange(0, longTextString.length];
//While there are still more occurrences of this keyword
//Not that the code both assigns the result to range, and evaluates the location.
//This is a bit of C language sleight-of-hand. It works, but is odd-looking code.
while ((range = [longTextString
rangeOfString: aKeyword
options: NSLiteralSearch
range: range]).location != NSNotFound)
{
//Set the attributes on this occurrence of this keyword.
[longTextString setAttributes: attrs range: range];
range.location = range.location+range.length;
range.length = longTextString - range.location;
}
Disclaimer: I typed out the code above in an editor window. It may not compile, much less run. It's intended for illustration purposes only. You will need to clean it up and adapt it to your needs.
Also note that rangeOfString:options:range is not a great choice for this problem, since it will detect word fragments in the middle of longer words. For example, if one of your keywords is "The" then it would detect "The" in the first 3 characters of "Them" and "These". It should really be rewritten to use regular expression string matching that requires a string to be a whole word.
Edit #2. I decided to actually code this up. The rangeOfString:options:range: approach is unsatisfactory because, as mentioned above, it detects word fragments inside larger words. Regular Expressions are a much better solution. Here is code that marks all occurrences of an array of words as bold:
NSMutableAttributedString *viewStyledText = [theTextView.attributedText mutableCopy];
NSString *viewText = viewStyledText.string;
if (viewText.length == 0)
return;
BOOL changed = NO;
NSArray *wordsToBold = #[#"The", #"for", #"to", #"league"];
UIFont *boldFont = [UIFont boldSystemFontOfSize: 15];
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
boldFont, NSFontAttributeName,nil];
//Loop through each keyword in the array of keywords.
for (NSString *wordToBold in wordsToBold)
{
//Set the range to the whole string to start with.
NSRange range = NSMakeRange(0, viewText.length);
/*
Create a regular expression string for the current word.
The "(?i) prefix tells the regular expression to be case-insenstive. Remove it if
you want your search to be case-sensitive.
The "\b" bits (with double backslashes so the output contains a backslash) cause
The regular expression to only match whole words.
*/
NSString *wordRegExString = [NSString stringWithFormat: #"(?i)\\b%#\\b", wordToBold];
//Now create a regular expression object using the current regular expression string.
NSRegularExpression *wordRegEx = [NSRegularExpression
regularExpressionWithPattern: wordRegExString
options: 0
error: nil];
//While there are still more occurrences of this keyword...
//Not that the code both assigns the result to range, and evaluates the location.
//This is a bit of C language sleight-of-hand. It works, but is odd-looking code.
while ((range = [wordRegEx rangeOfFirstMatchInString: viewText
options: 0
range: range]).location != NSNotFound)
{
//Set the attributes on this occurrence of this keyword.
changed = YES;
[viewStyledText setAttributes: attrs range: range];
range.location = range.location+range.length;
range.length = viewStyledText.length - range.location;
}
}
if (changed)
theTextView.attributedText = viewStyledText;

Related

Dynamic Number of UILabels in custom tableviewcell

I created a custom tableview cell and I want to display some strings in that cell. I fetch strings from backend thus I don't know how many labels I needed. I tried to concat strings in one label and implemented like below however I want to display strings with different attributes after char ":".
for (AttributesModel* attribute in model.attributes) {
NSString *attributeName = attribute.name;
attributeString = [[attributeString stringByAppendingString: attributeName] mutableCopy];
attributeString = [[attributeString stringByAppendingString: #" : "] mutableCopy];
for (NSDictionary *value in attribute.options) {
attributeString = [[attributeString stringByAppendingString: [value objectForKey:#"name"] ] mutableCopy];
attributeString = [[attributeString stringByAppendingString: #", "] mutableCopy];
}
attributeString = [[attributeString stringByAppendingString: #"\n"] mutableCopy];
}
I could not change attributes of strings thats located after char ":".
Are there any way to do that? Can I create dynamic number of labels in cell or only change attributes of strings that are only located after ":" ?
It sounds like you want to change the attributes such as formatting of a section of text within a UILabel. You can do this by:
Creating an attributed, mutable copy of your string (a.k.a converting an NSString into an NSMutableAttributedString).
Changing the attributes to parts of this copy.
Setting your label's attributedText property to your attributed string.
NSString *myString = #"This is my string";
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:myString];
NSMutableAttributedString *mutableAttributedString = [attributedString mutableCopy];
// The range of text to change, i.e. start from the 5th index
// (starting from 0 like arrays), and continue for 2 characters:
NSRange rangeOfSecondWord = NSMakeRange(5, 2);
// The list of attributes to apply to that range:
NSDictionary *myAttributes = #{
NSForegroundColorAttributeName : [UIColor redColor],
};
// Actually apply the attributes:
[mutableAttributedString setAttributes:myAttributes range:rangeOfSecondWord];
// Set the text of the label to the attributed string:
myLabel.attributedText = mutableAttributedString;
For a list of attributes that you can set in your dictionary, see the Character Attributes reference.
Since you're downloading your strings, you may not know the range beforehand. Since you're concatenating them, here is how you can find the range dynamically:
NSString *stringOne = #"My name is ";
NSString *stringTwo = #"John Citizen";
NSString *joinedStrings = [stringOne stringByAppendingString:stringTwo];
NSRange rangeOfStringTwo = [joinedStrings rangeOfString:stringTwo];

How to detect emoji and change font size

I have text which contains emoji in it, we are able to display it correctly by doing encoding and decoding the string, what I need to achieve is to increase the font size of only emoji in the text like in image below,
I have got an idea to determine the range of all emoji, and supply in NSAttributedString with increased font size. Now am out of idea how can I detect range of emojis in a given string?
Thanks
I have done the same like
let string = "This is emoji Test"
let attributedEmoji = NSMutableAttributedString(string: " \u{1F600}", attributes: [NSFontAttributeName:UIFont.systemFontOfSize(60)])
let attribString = NSMutableAttributedString.init(string: string)
attribString.appendAttributedString(attributedEmoji)
lblEmoji.attributedText = attribString
You can change the font and font size to scale the emoji.
Put all possible Emoji's(Your application uses) into an array.
Search for emoji into string from array.If found apply attributed Emoji.
Write a method that accept emoji code and return attributed emoji text.
Hope this info will help you in better way.
https://github.com/woxtu/NSString-RemoveEmoji
Find out if Character in String is emoji?
you can use it directly like below or
if ([myString containsString:#"😋"])
{
NSLog(#"one");
//change the font size here.
}
else
{
NSLog(#"fk");
//change the font size here.
}
or you can use
[mystring is isEqualToString:"I believe 😋"];
try those. hope this will help to you.
I have made one demo, You can detect emoji from the string like below,
NSString *str = #"this is 😄 and test 😊";
NSArray *arr = [str componentsSeparatedByString:#" "];
for (int i = 0; i < arr.count; i++) {
NSString *temp = [arr objectAtIndex:i];
if ( ![temp canBeConvertedToEncoding:NSASCIIStringEncoding]) {
NSLog(#"%d",i);
NSLog(#"%#",temp); // temp is emoji. You can detect emoji here from your string now you can manage as per your need
}
}
Thanks to all who answered, but none was complete answer though #Raj's suggestion to look NSString-RemoveEmoji helped me to achieve the solution for this, here it is, it works for any kind of emoji
-(NSMutableAttributedString *)getAttributedEmojiString:(NSString *)inputString{
NSMutableArray *__block emojiRange=[[NSMutableArray alloc] init];
[inputString enumerateSubstringsInRange:NSMakeRange(0, [inputString length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock: ^(NSString* substring, NSRange substringRange, NSRange enclosingRange, BOOL* stop) {
if([substring isEmoji]){
[emojiRange addObject:#{#"startrange":#(substringRange.location),#"endrange":#(enclosingRange.length)}];
}
}];
NSMutableAttributedString *mutString=[[NSMutableAttributedString alloc] initWithString:inputString];
[mutString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16.0] range:NSMakeRange(0, mutString.length)];
[emojiRange enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[mutString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:35.0] range:NSMakeRange([obj[#"startrange"] floatValue], [obj[#"endrange"] floatValue])];
}];
return mutString;
}
Description
First find NSRange of all the emoji in the string by using NSString-RemoveEmoji function isEmoji, and store in array.
Supply the fetched range to apply bigger FONT SIZE to characters in the range.
Finally assign the generated attributed text to the label.
self.label.attributedText=[self getAttributedEmojiString:EmojiDecoded(originalText)];
I use two macros to Encode and Decode Emoji's since I need to save these values to server and read through api, below are the macros.
#define Encoded(val) [[val dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]
#define Decoded(val) [[NSString alloc] initWithData:[[NSData alloc] initWithBase64EncodedString:val options:0] encoding:NSUTF8StringEncoding]
#define EmojiEncoded(val) [[NSString alloc] initWithData:[val dataUsingEncoding:NSNonLossyASCIIStringEncoding] encoding:NSUTF8StringEncoding]
#define EmojiDecoded(val) [[NSString alloc] initWithData:[val dataUsingEncoding:NSUTF8StringEncoding] encoding:NSNonLossyASCIIStringEncoding]
Hope it helps anyone who is looking for similar solution.
Cheers, and thanks to all.
This is somewhat late but might be useful for other folks who stumble upon this answer. The secret is to ask Core Text and it knows which characters in the NSAttributedString are emoji characters.
// Build the attributed string as needed
let ns = NSAttributedString(string: s)
// Now create a typesetter and render the line
let typesetter = CTTypesetterCreateWithAttributedString(nsa)
let line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, nsa.length))
// Once you have a line you can enumerate the runs
guard let runs = CTLineGetGlyphRuns(line) as? [CTRun] else {
throw NSError(domain: "CoreText", code: -1, userInfo: nil)
}
// Each run will have a font with specific attributes
print("There are \(runs.count) run(s) in \(ns.string)")
print()
for run in runs {
let charRange = CTRunGetStringRange(run)
let x: NSAttributedString = CFAttributedStringCreateWithSubstring(nil, nsa, charRange)
print(" Chars: '\(x.string)'")
let attributes: NSDictionary = CTRunGetAttributes(run)
let font = attributes["NSFont"] as! CTFont
let traits = CTFontGetSymbolicTraits(font)
print(" Emoji == \(traits.contains(.traitColorGlyphs))")
print()
}

Iterating format % placeholders one by one

I've got an NSAttributedString that looks like
"Somestring bold %# template %f %d blah blah blah"
I want to be able to replace the format template parts just like in [NSString stringWithFormat:...] but keeping the styling, so that the replaced strings match the styling around them (all bold in my example above).
Is there a way to iterate through each format % placeholder one by one so I can use a list of arguments to fill the string?
I don't want to build my own % implementation because I know theres a million and one different formats.
Or is there an easier solution that I'm overlooking?
Edit:
I'll explain a bit of the complete solution I'm solving:
To make it possible for my team to attribute localized strings I've already got a way to write
"key"="test //italic %#// **bold** __underline %d__";
If a specifier is between attributed tags I want that part to be attributed. Currently I can create an attributed string as seen above, the next part is to take care of the specifiers left over.
I'm doing it in the order of Parse attributes -> Apply arguments..., I could easily solve it the other way but I don't want format arguments to mess with the attributes
Big thanks to #Rick for pointing me in the right direction.
His post recommends first going over the arguments and pre-escaping any string or character objects before applying the format strings. This brought me back to another problem I was having earlier, in trying to iterate an argument list of different types (NSString, int etc), like NSLog does. I think I found that it is impossible (or at least really difficult) to do this, and the reason NSLog can is that it knows what types to expect through the format specifiers (%#, %i etc).
I realize I can actually get the same effect not by escaping the arguments, but by escaping the format string itself.
Example:
format: "test //italic %#//"
args: "text // more text"
Steps:
First replace all instances of // with //-TAG-//
Apply the arguments
Determine where styling applies between //-TAG-//
Obviously //-TAG-// can still be written in the arguments to mess up the styling, however depending on what you use as a replacement, the chances of this happening are essentially zero.
I'm doing it in the order of Parse attributes -> Apply arguments..., I
could easily solve it the other way but I don't want format arguments
to mess with the attributes
Why not simply add an escape-character? From what I understand you run the risk of the example you provided getting messed up if the first string contains a double slash?
"key"="test //italic %#// **bold** __underline %d__";
if %# is text // more text that would screw up the formatting.
If so, then simply parse every vararg of the type NSString and char to make sure that they don't contain any of the characters you reserved for your attributes. If they do, add some escape char before which you remove upon parsing the attributes.
The above example would look like this after applying the arguments:
"key"="test //italic text \/\/ more text// **bold** __underline 34__";
After which you parse the attributes, same way as before but you ignore characters preceded by \ and make sure to remove the \.
It's a bit of effort but I bet it's a lot less than implementing your own printf-style parser.
Here is working code:
#import <Foundation/Foundation.h>
#interface NSAttributedString (AttributedFormat)
- (instancetype)initWithFormat:(NSAttributedString *)attrFormat, ...;
- (instancetype)initWithFormat:(NSAttributedString *)attrFormat arguments:(va_list)arguments;
#end
#implementation NSAttributedString (AttributedFormat)
- (instancetype)initWithFormat:(NSAttributedString *)attrFormat, ... {
va_list args;
va_start(args, attrFormat);
self = [self initWithFormat:attrFormat arguments:args];
va_end(args);
return self;
}
- (instancetype)initWithFormat:(NSAttributedString *)attrFormat arguments:(va_list)arguments {
NSRegularExpression *regex;
regex = [[NSRegularExpression alloc] initWithPattern: #"(%.*?[#%dDuUxXoOfeEgGccsSpaAF])"
options: 0
error: nil];
NSString *format = attrFormat.string;
format = [regex stringByReplacingMatchesInString: format
options: 0
range: NSMakeRange(0, format.length)
withTemplate: #"\0$1\0"];
NSString *result = [[NSString alloc] initWithFormat:format arguments:arguments];
NSMutableArray *f_comps = [format componentsSeparatedByString:#"\0"].mutableCopy;
NSMutableArray *r_comps = [result componentsSeparatedByString:#"\0"].mutableCopy;
NSMutableAttributedString *output = [[NSMutableAttributedString alloc] init];
__block int consumed_length = 0;
[attrFormat enumerateAttributesInRange:NSMakeRange(0, attrFormat.length) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
NSMutableString *substr = [NSMutableString string];
while(f_comps.count > 0 && NSMaxRange(range) >= consumed_length + [(NSString *)f_comps[0] length]){
NSString *f_str = f_comps[0];
NSString *r_str = r_comps[0];
[substr appendString:r_str];
[f_comps removeObjectAtIndex:0];
[r_comps removeObjectAtIndex:0];
consumed_length += f_str.length;
}
NSUInteger idx = NSMaxRange(range) - consumed_length;
if(f_comps.count > 0 && idx > 0) {
NSString *f_str = f_comps[0];
NSString *leading = [f_str substringToIndex:idx];
[substr appendString:leading];
NSString *trailing = [f_str substringFromIndex:idx];
[f_comps replaceObjectAtIndex:0 withObject:trailing];
[r_comps replaceObjectAtIndex:0 withObject:trailing];
consumed_length += idx;
}
[output appendAttributedString:[[NSAttributedString alloc] initWithString:substr attributes:attrs]];
}];
return [self initWithAttributedString:output];
}
#end
Usage example:
NSMutableAttributedString *fmt = [[NSMutableAttributedString alloc] initWithString:#"test: "];
[fmt appendAttributedString: [[NSAttributedString alloc] initWithString: #"Some%%string"
attributes: #{
NSFontAttributeName: [UIFont systemFontOfSize:17]
}]];
[fmt appendAttributedString: [[NSAttributedString alloc] initWithString: #"bold %# template %.3f %d"
attributes: #{
NSFontAttributeName: [UIFont boldSystemFontOfSize:20],
NSForegroundColorAttributeName: [UIColor redColor]
}]];
[fmt appendAttributedString: [[NSAttributedString alloc] initWithString: #"%# blah blah blah"
attributes: #{
NSFontAttributeName: [UIFont systemFontOfSize:16],
NSForegroundColorAttributeName: [UIColor blueColor]
}]];
NSAttributedString *result = [[NSAttributedString alloc] initWithFormat:fmt, #"[foo]", 1.23, 56, #"[[bar]]"];
Result:
Maybe this still have some bugs, but it should work in most cases.
(%.*?[#%dDuUxXoOfeEgGccsSpaAF])
This regex matches "Format Specifiers". specifier begin with % and end with listed characters. and may have some modifiers between them. It's not perfect, for example this illegal format "%__s" should be ignored but my regex matches this whole string. but as long as the specifier is legal one, it should works.
My code matches it, and insert delimiters around the specifiers:
I'm %s.
I'm <delimiter>%s<delimiter>.
I use \0 as a delimiter.
I'm \0%s\0.
then interpolate it.
I'm \0rintaro\0.
then split the format and the result with the delimiter:
f_comps: ["I'm ", "%s", "."]
r_comps: ["I'm ", "rintaro", "."]
Here, total string length of f_comps is exact the same as original attributed format. Then, iterate the attributes with enumerateAttributesInRange, we can apply the attributes to the results.
I'm sorry but it's too hard to explain the jobs inside enumerateAttributesInRange, with my poor English skills :)

How can I find a font that contains a given character?

I have a font that I use for my app which only uses english characters. I use CoreText to display the text, and I notice that whenever someone enters a character that isn't included in the font (like an Arabic character), then the program hangs at this line:
CTFramesetterCreateFrame(textFramesetter, CFRangeMake(0, 0), textMutablePath, NULL);
I have a couple of questions:
is it possible to know if a certain character is included in a font?
is it possible for the system to find a font that contains the unknown character?
Related: Check if certain character is supported by UIFont
1) Is it possible to know if a certain character is included in a font?
BOOL FontContainsCharacter(UIFont *font, unichar character) {
NSCharacterSet *characterSet = [font.fontDescriptor objectForKey:UIFontDescriptorCharacterSetAttribute];
return [characterSet characterIsMember:character];
}
2) Is it possible for the system to find a font that contains the unknown character?
NSArray *FontDescriptorsForFontsContainingCharactersInString(NSString *string) {
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:string];
NSDictionary *fontAttributes = #{UIFontDescriptorCharacterSetAttribute:characterSet};
UIFontDescriptor *fontDescriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:fontAttributes];
return [fontDescriptor matchingFontDescriptorsWithMandatoryKeys:nil];
}
For example:
NSLog(#"%d", FontContainsCharacter([UIFont fontWithName:#"Helvetica" size:12], 0x0041)); // "A"
NSLog(#"%d", FontContainsCharacter([UIFont fontWithName:#"Helvetica" size:12], 0x4F60)); // "ä½ "
for (UIFontDescriptor *fontDescriptor in FontDescriptorsForFontsContainingCharactersInString(#"你好")) {
NSLog(#"%#", [UIFont fontWithDescriptor:fontDescriptor size:12].fontName);
}
Output:
1
0
STHeitiSC-Light
STHeitiSC-Medium
STHeitiTC-Light
STHeitiTC-Medium
HiraKakuProN-W3
HiraKakuProN-W6
HiraMinProN-W3
HiraMinProN-W6
I found the answer to my first question and is based on a response from Rob Mayoff in this other question: CTFontGetGlyphsForCharacters always returns false
- (BOOL) textExistsInFont:(NSString *)text
{
CTFontRef fontRef = CTFontCreateWithName((__bridge CFStringRef)self.fontName, self.fontSize, NULL);
NSUInteger count = text.length;
unichar characters[count];
[text getCharacters:characters range:NSMakeRange(0, count)];
CGGlyph glyphs[count];
if (CTFontGetGlyphsForCharacters(fontRef, characters, glyphs, count) == false)
{
return NO;
}
else
{
return YES;
}
}
My second question I'm still working on but am getting the impression that the Apple system font (Helvetica Neue) covers many languages. Want to verify though. So if the character isn't in the font you're using, then switching to the system font might be a viable alternative.

Change attributes of substrings in a NSAttributedString

This question may be a duplicate of this one. But the answers don't work for me and I want to be more specific.
I have a NSString, but I need a NS(Mutable)AttributedString and some of the words in this string should be given a different color. I tried this:
NSString *text = #"This is the text and i want to replace something";
NSDictionary *attributes = # {NSForegroundColorAttributeName : [UIColor redColor]};
NSMutableAttributedString *subString = [[NSMutableAttributedString alloc] initWithString:#"AND" attributes:attributes];
NSMutableAttributedString *newText = [[NSMutableAttributedString alloc] initWithString:text];
newText = [[newText mutableString] stringByReplacingOccurrencesOfString:#"and" withString:[subString mutableString]];
The "and" should be uppercase an red.
The documentation says that mutableString keeps the attribute mappings. But with my replacing-thing, I have no more attributedString on the right side of the assignment (in the last line of my code-snippet).
How can I get what I want? ;)
#Hyperlord's answer will work, but only if there is one occurence of the word "and" in the input string. Anyway, what I would do is use NSString's stringByReplacingOccurrencesOfString: initially to change every "and" to an "AND", then use a little regex to detect matches in attributed string, and apply NSForegroundColorAttributeName at that range. Here's an example:
NSString *initial = #"This is the text and i want to replace something and stuff and stuff";
NSString *text = [initial stringByReplacingOccurrencesOfString:#"and" withString:#"AND"];
NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:text];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(AND)" options:kNilOptions error:nil];
NSRange range = NSMakeRange(0,text.length);
[regex enumerateMatchesInString:text options:kNilOptions range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange subStringRange = [result rangeAtIndex:1];
[mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:subStringRange];
}];
And finally, just apply the attributed string to your label.
[myLabel setAttributedText:mutableAttributedString];
I think you should create a NSMutableAttributedString using the existing NSString and then add the style attributes with the appropriate NSRange in order to colorize the parts you want to emphasize for example:
NSString *text = #"This is the text and i want to replace something";
NSMutableAttributedString *mutable = [[NSMutableAttributedString alloc] initWithString:text];
[mutable addAttribute: NSForegroundColorAttributeName value:[UIColor redColor] range:[text rangeOfString:#"and"]];
Be aware: this is just from my head and not tested at all ;-)
Please try this code in Swift 2
var someStr = "This is the text and i want to replace something"
someStr.replaceRange(someStr.rangeOfString("and")!, with: "AND")
let attributeStr = NSMutableAttributedString(string: someStr)
attributeStr.setAttributes([NSForegroundColorAttributeName: UIColor.yellowColor()], range: NSMakeRange(17, 3) )
testLbl.attributedText = attributeStr
Here's another implementation (in Swift) that's helpful if you're doing some more complex manipulations (such as adding/deleting characters) with your attributed string:
let text = "This is the text and i want to replace something"
let mutAttrStr = NSMutableAttributedString(string: text)
let pattern = "\\band\\b"
let regex = NSRegularExpression(pattern: pattern, options: .allZeros, error: nil)
while let result = regex!.firstMatchInString(mutAttrStr.string, options: .allZeros, range:NSMakeRange(0, count(mutAttrStr.string)) {
let substring = NSMutableAttributedString(attributedString: mutAttrStr.attributedSubstringFromRange(result.range))
// manipulate substring attributes here
substring.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range NSMakeRange(0, count(substring.string))
mutAttrStr.replaceCharactersInRange(result.range, withAttributedString: substring)
}
Your final attributed string should be:
let finalAttrStr = mutAttrStr.copy() as! NSAttributedString

Resources