Christian
Christian

Reputation: 526

xcode iOS NSMutableAttributedString add attribute more than one time

I want to show the english date styled. I made the following code to get the characters to "redesign":

    - (NSMutableAttributedString *)attributedInfoString:(NSString *)string;
    {
        NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:string];
        UIFont *smallFont = [UIFont boldSystemFontOfSize:17.0f];
        UIFont *boldFont = [UIFont fontWithName:@"HelveticaNeue-Bold" size:24.0f];

        [attString beginEditing];

        [attString addAttribute:NSFontAttributeName value:(smallFont) range:[string rangeOfString:@"th"]];
        [attString addAttribute:NSFontAttributeName value:(smallFont) range:[string rangeOfString:@"th" options:NSBackwardsSearch]];
        [attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@"1" range:[string rangeOfString:@"th"]];
        [attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@"1" range:[string rangeOfString:@"th" options:NSBackwardsSearch]];

        [attString addAttribute:NSFontAttributeName value:(boldFont) range:[string rangeOfString:@"the"]];
        [attString addAttribute:NSFontAttributeName value:(boldFont) range:[string rangeOfString:@"the" options:NSBackwardsSearch]];
        [attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@"0" range:[string rangeOfString:@"the"]];
        [attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@"0" range:[string rangeOfString:@"the" options:NSBackwardsSearch]];

        [attString addAttribute:NSFontAttributeName value:(smallFont) range:[string rangeOfString:@"st"]];
        [attString addAttribute:NSFontAttributeName value:(smallFont) range:[string rangeOfString:@"st" options:NSBackwardsSearch]];
        [attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@"1" range:[string rangeOfString:@"st"]];
        [attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@"1" range:[string rangeOfString:@"st" options:NSBackwardsSearch]];

        [attString addAttribute:NSFontAttributeName value:(boldFont) range:[string rangeOfString:@"August"]];
        [attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@"0" range:[string rangeOfString:@"August"]];

...

        [attString endEditing];
        return attString;
    }

The problem, I find only the first "hit" from the beginning or from the end. How can I arrange to search the whole string? Especially concerning the "th" because in the string is sometimes 5 or 6 times the word "the" which then stops the adding of the attributes.

Upvotes: -1

Views: 891

Answers (3)

Christian
Christian

Reputation: 526

Thanks to 0yeoj I found the solution:

  1. In the strings delete the opening-tag and replace the closing-tag by unique characters, that no word would have in this order (öäüß).

  2. Use the code from 0yeoj to find the string "thöäüß", stöäüß etc. and add the attributes as desired.

  3. Here my error took place - I tried to delete the characters "öäüß" in the sub-loop which causes always a crash.

  4. Found the solution in another post here and placed it just before the return-expression:

    while ([attriString.string containsString:@"öäüß"]) { NSRange rangeOfTag = [attriString.string rangeOfString:@"öäüß"]; [attriString replaceCharactersInRange:rangeOfTag withString:@""]; }

Works now perfect. Thanks for the fast help.

Upvotes: 0

0yeoj
0yeoj

Reputation: 4550

I'm not sure of what you want to achieve. But this is what I usually use for adding attribute for a long string.

- (NSMutableAttributedString *)attributedInfoString:(NSString *)string;
{
    __block NSMutableAttributedString *attriString = [[NSMutableAttributedString alloc] initWithString:string];

    [attriString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15.0f] range:NSMakeRange(0, string.length)];

    UIFont *bold = [UIFont boldSystemFontOfSize:17.0f];

    __block BOOL mustStop = NO;

    [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                               options:NSStringEnumerationByWords
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop)
     {
         // terminates adding of attribute to string if YES
         // as you can see `og` from the word dog is ignored
         if (!mustStop)
         {
             // since we are enumeratingByWord this is to check for specific string(word) in the `string`
             // in this example `the` is the trigger to terminate adding attributes to mutableString
             //
             if (![substring isEqual:@"the"])
             {
                 // add attribute if the substring(word) has `ox` or `og`
                 //
                 if ([substring rangeOfString:@"ox"].location != NSNotFound || [substring rangeOfString:@"og"].location != NSNotFound)
                 {
                     [attriString addAttribute:NSFontAttributeName value:bold range:substringRange];
                 }

                 else
                 {
                     // this is to add attribute to some specified `substring`
                     //
                     NSString *subsubString = @"uic";

                     NSRange subRange = [substring rangeOfString:subsubString];

                     if (subRange.location != NSNotFound)
                     {
                         substringRange.location += subRange.location;

                         substringRange.length = subsubString.length;

                         [attriString addAttribute:NSForegroundColorAttributeName value:[UIColor orangeColor] range:substringRange];

                         [attriString addAttribute:NSFontAttributeName value:bold range:substringRange];
                     }
                 }
             } else mustStop = YES;
         }
     }
     ];

    return attriString;
}

If you use that like:

title.attributedText = [self attributedInfoString:@"The quick brown fox jumped over the lazy dog"];

sample output would be:

enter image description here

Hope this would help.. Cheers! :)

Upvotes: 1

David Dunham
David Dunham

Reputation: 8329

If you find "th", keep looping using -rangeOfString:options:range: (where you set the range argument to just past where you found it).

Upvotes: 1

Related Questions