Objective-C: Equivalent to stringWithFormat for NSMutableAttributedString - ios

I am trying to add a hyperlink in a string. I have a localized string and I put %# to format my string. When I add the attributed string into my string, the attributed format gives the raw result which is NSLink = "https://www.example.com". I could not find an attributed string formatter the same as the string formatter. How can I achieve the same behaviour in my case?
Code:
NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:#"Example"];
[str addAttribute: NSLinkAttributeName value: #"https:/www.example.com" range: NSMakeRange(0, str.length)];
NSMutableAttributedString *originalStr = [[NSMutableAttributedString alloc] initWithString: self.pageDescriptions[3].localized];
pageContentViewController.messageText = [NSString stringWithFormat:self.pageDescriptions[index].localized, str];

stringWithFormat: is only doing substitutions of formatters. So if your formatters are simple enough, like a %#, you can just search for it with rangeOfString: and do the substitution yourself with replaceCharactersInRange:withAttributedString:.
NSMutableAttributedString *strWithLink = [[NSMutableAttributedString alloc] initWithString:#"Example"];
[strWithLink addAttribute:NSLinkAttributeName value:#"https:/www.example.com" range:NSMakeRange(0, strWithLink.length)];
NSMutableAttributedString *strWithFormat = [[NSMutableAttributedString alloc] initWithString:#"hello %# world"];
[strWithFormat replaceCharactersInRange:[strWithFormat.string rangeOfString:#"%#"] withAttributedString:strWithLink];
The result here in strWithFormat kept the attributes of strWithLink.
Note: this won't work correctly if your format is complex, like with %%# %# %%#, because it will replace the first occurrence of %#, while stringWithFormat: would have replaced the middle occurrence.

There isn't one. You create the NSAttributedString by hand, or you create an extension that does what you want if you do this a lot.

Related

Replace character in NSMutableAttributedString

This works for a regular NSString:
NSString *newString = [myString stringByReplacingOccurrencesOfString:#"," withString:#""];
But there is no such method for NSMutableAttributedString. How could I remove all instances of a comma in an NSMutableAttributedString?
let attrString = NSMutableAttributedString(string: "Hello <b>friend<b>")
attrString.mutableString.replaceOccurrencesOfString("<b>", withString: "", options: NSStringCompareOptions.CaseInsensitiveSearch, range: NSRange(location: 0, length: attrString.length))
Try this :)
Do it before you create the attributed string, if you can or depending on how you source it. If you can't then you can use replaceCharactersInRange:withString: (or replaceCharactersInRange:withAttributedString:), but you need to know the range so you need to search and iterate yourself.
NSString *newString= "I want to ,show, you how to achieve this";
NSMutableAttributedString *displayText = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"%#",newString]];
[[displayText mutableString] replaceOccurrencesOfString:#"," withString:#"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, displayText.string.length)];
You can initialize the attributed string with the stripped string with the designed init. No?
The code could be applied from my answer here:
NSAttributedString *attributedString = ...;
NSAttributedString *anotherAttributedString = ...; //the string or characters which will replace
while ([attributedString.mutableString containsString:#"replace"]) {
NSRange range = [attributedString.mutableString rangeOfString:#"replace"];
[attributedString replaceCharactersInRange:range withAttributedString:anotherAttributedString];
}

Add a nsstring at the end of attributed string in textview iOS

I have a text like "Hello There" which will be a attributed string with red color. Then at the end of that attributed string I want to append a nsstring 'Who are you?' But whenever I append a nsstring, the whole string becomes normal nsstring and the property of the attributed string is being removed. My attempt so far:
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:#"Hello There"];
[attributeString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,[attributeString length])];
NSMutableAttributedString *previousAttrString = [[NSMutableAttributedString alloc] initWithString:messageTextView.text];
[previousAttrString insertAttributedString: attributeString atIndex:location];
messageTextView.attributedText = previousAttrString;
messageTextView.font = [UIFont fontWithName:#"Helvetica" size:15];
NSString *messageWithContact = [NSString stringWithFormat: #"%# %#", messageTextView.text, #"Who are you?"];
messageTextView.text=messageWithContact;
What I did wrong? Please help me.
Replace the bottom lines
NSString *messageWithContact = [NSString stringWithFormat: #"%# %#", messageTextView.text, #"Who are you?"];
messageTextView.text=messageWithContact;
with
NSMutableAttributedString *newString = messageTextView.attibutedText;
[newString appendAttributedString: [[NSAttributedString alloc] initWithString: #"Who are you?"];
messageTextView.attibutedText = newString;

How to change case of an NSMutableAttributedString in Objective-C?

I have a NSMutableAttributedString that contain values in lower case letters. I need to convert all the lowercase letters to uppercase. We can solve this using uppercaseString for normal string as:
[string uppercaseString];
How can I change my case for NSMutableAttributedString? Thanks!
Hope the below code snippet may help you
NSMutableAttributedString * linkString = [[NSMutableAttributedString alloc]initWithString:#"Google"];
NSString * strings = [[linkString string]uppercaseString];
[linkString replaceCharactersInRange:NSMakeRange(0, [linkString length]) withString:strings];
NSLog(#"UpperCase %#",linkString);
NSMutableAttributedString class doesn't have uppercaseString method. So you can use like this..
NSString *str = #"objective-c";
str = [str uppercaseString];
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:str];
NSLog(#"Attributed String %#",attStr);
And You wanna upper latter in particular range then do something like this...
[attStr replaceCharactersInRange:NSMakeRange(0, 1) withString:#"O"];

Display edited NSString in order

I have been working on this for a few days with help from this great community.
I have a NSArray that I need to edit NSStrings within. I have managed to detect a marker in the string and make it bold. However now I am trying to display the strings in the order that they are within the NSArray whilst maintaining the Bold that was added to the specific strings.
I can display the individual Bold String 'string' but I need it to be in order that it is within the array. I know of stringByAppendingString but this would put it at the end.
Any directions would be brilliant.
for (NSString *testWord in legislationArray) {
if ([testWord rangeOfString:#"BOLDME"].location != NSNotFound) {
//Remove Marker
NSString *stripped = [testWord stringByReplacingOccurrencesOfString:#"BOLDME" withString:#""];
//Get string and add bold
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:stripped];
NSRange selectedRange = [stripped rangeOfString:(stripped)];
[string beginEditing];
[string addAttribute:NSFontAttributeName
value:[UIFont fontWithName:#"Helvetica-Bold" size:18.0]
range:selectedRange];
[string endEditing];
//Where to go now with string?
}
}
cell.dynamicLabel.text = [legislationArray componentsJoinedByString:#"\n"];
EDIT
Based on the answers below I got it working however the bold method invokes this error:
componentsJoinedByString return a NSString, when you want a NSAttributedString.
Plus, you're setting your text to a receiver that awaits a NSString (cell.dynamicLabel.text), where what you want should be cell.dynamicLabel.attributedText.
Since there is no equivalent to componentsJoinedByString for a NSAttributedString return, you have to do it the oldway, with a for loop, starting with initializing a NSMutableAttributedString, and adding to it each components (that you may "transform") to it.
Here is a example and related question.
Just use additional array. Change your code to
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] init];
for (NSString *testWord in legislationArray) {
if ([testWord rangeOfString:#"BOLDME"].location != NSNotFound) {
//Remove Marker
NSString *stripped = [testWord stringByReplacingOccurrencesOfString:#"BOLDME" withString:#""];
//Get string and add bold
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:stripped];
NSRange selectedRange = [stripped rangeOfString:(stripped)];
[string beginEditing];
[string addAttribute:NSFontAttributeName
value:[UIFont fontWithName:#"Helvetica-Bold" size:18.0]
range:selectedRange];
[string endEditing];
//Where to go now with string?
[attrString appendAttributedString:string];
}
else
{
[attrString appendAttributedString:[[NSAttributedString alloc] initWithString:testWord]];
}
// NEW LINE
[attrString appendAttributedString:[[NSAttributedString alloc] initWithString:#"\n"]];
}
cell.dynamicLabel.attributedText = attrString;
UPDATE:
Your additional issue is not a error - this is a way how XCode shows attributed strings in debug window:

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