6

In my app the User will type anything that he wants and he can make the text Bold, Italic and Underline.

I am able to do the Text - Bold, Italic and Underline.

But I need to find which Text (or Character) is Bold, Italic and Underline from the attribute string that user typed.

Any types of link, tutorial, code will be great help.

EDIT :

I need the result like this...

if character 6 is Italic then print Italic.
if character 14 is Bold then print Bold.

I need to convert all the text from Calibri font family to HelveticaNeue font family without changing it's attribute.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Sam
  • 431
  • 7
  • 23

1 Answers1

14

You can enumerate the Attributes with this code (whole range).

[attrStr enumerateAttributesInRange:NSMakeRange(0, [attrStr length]) options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:
         ^(NSDictionary *attributes, NSRange range, BOOL *stop) {
//Do something here
             }
         }];

For specific range, your have to change the code NSMakeRange(0, [attrStr lenght]) by the range you need.

After your edit, your specific need, this code should do the work:

[attrStr enumerateAttributesInRange:NSMakeRange(0, [attrStr length])
                            options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
                         usingBlock:
 ^(NSDictionary *attributes, NSRange range, BOOL *stop)
{
     NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
     UIFont *currentFont = [mutableAttributes objectForKey: NSFontAttributeName];
     UIFont *newFont;
     if ([[currentFont fontName] isEqualToString:@"Calibri-BoldItalic"])
         newFont = [UIFont fontWithName:@"HelveticaNeue-BoldItalic" size:currentFont.pointSize];
     else if ([[currentFont fontName] isEqualToString:@"Calibri-Bold"])
         newFont = [UIFont fontWithName:@"HelveticaNeue-Bold" size:currentFont.pointSize];
     else if ([[currentFont fontName] isEqualToString:@"Calibri-Italic"])
         newFont = [UIFont fontWithName:@"HelveticaNeue-Italic" size:currentFont.pointSize];
    [mutableAttributes setObject:newFont forKey:@"NSFont"];
    [attrStr setAttributes:mutableAttributes range:range];
 }];

From your comments, you may see more complicated things, so I will give you some ideas/tips to do/check. You'll just have to complete my previous code to manage all cases.
• Case: There is no font.
You just have to check if currentFont is nil. If yes, you set what you want. Since there is no attribute for italic/bold (since they are "included" in the font), I suggest you set for newFont: HelveticaNeue.
• Case: It's another font than Calibri. There it's quite more complicated.
I've worked with that, and here what I got: Font name (which is the postscript name) is made like this for HelveticaNeue (as given example):

HelveticaNeue
HelveticaNeue-Light
HelveticaNeue-UltraLight
HelveticaNeue-Medium
HelveticaNeue-LightItalic
HelveticaNeue-Italic
HelveticaNeue-UltraLightItalic
HelveticaNeue-Bold
HelveticaNeue-BoldItalic
HelveticaNeue-CondensedBold
HelveticaNeue-CondensedBlack

So the first thing you could think of: I just have to check the suffix of the name (with hasSuffix:). But that may go wrong.
Indeed, some fonts have a foundry suffix (the ones I found are LT, MT, and EF).
Well, for example:
Times New Roman "real name" is TimesNewRomanPSMT.
And its italic version is TimesNewRomanPS-ItalicMT
That's why we have to check if it has a foundry suffix because TimesNewRomanPSMT-Italic won't work (since it doesn't exist, if you try to set a font with this name, it will be nil).
So, as far as I know, and as far I may have some experience and the case I've seen, what you could do: Check if the [currentFont name] contains either: BoldItalic, Italic or Bold, using a NSRegularExpression or a rangeOfString:. Note that I'd suggest to check before for BoldItalic since an Italic may "hides" a Bold just before it, and Bold may "hides" an Italic just after it.
In order to do so, I'd suggest that you create a method like this (or of this style):

-(UIFont)getCorrespondingHelveticaNeueFontMatchingCharacteriticsOf:(UIFont *)font
{
    UIFont *helveticaNueue;
    if (!font) //Checking if there is a font)
    {
        helveticaNueue = [UIFont fontWithName@"HelveticaNueue" size:defaultSizeYouSet];
    }
    else
    {
        //Check if it's BoldItalic/Italic/Bold
    }
    return helveticaNueue;
}

checking all the case I mentioned before.
So, from the previous code, you'll just have to replace the if tests that were working specificly for Calibri with:

UIFont *newFont = [self getCorrespondingHelveticaNeueFontMatchingCharacteriticsOf:currentFont];

Now a third part you may want to do (and add them to your test): Is the Black case of a font want to be managed as Bold? Well, Helvetica Neue has this "property", but you may want to use directly the black property for Helvetica Neue, and may want to check if currentFont has it (and again, another case).

EDIT: You can use since iOS7 we can use UIFontDescriptor. Here is what you could do:

-(UIFont *)customFontMatchingFont:(UIFont *)otherFont
{
    NSString *customFontName = @"Helvetica"; //The custom font
    UIFont *tempFont = [UIFont fontWithName:customFontName size:[otherFont pointSize]]; 
    return [UIFont fontWithDescriptor:[[tempFont fontDescriptor] fontDescriptorWithSymbolicTraits:[[otherFont fontDescriptor] symbolicTraits]] size:[otherFont pointSize]];
}

Note: I didn't check all the cases (what if your custom family doesn't have a matching font, what does it return? etc.), but that could be a nice add-on if you don't do too complicated things.

Larme
  • 24,190
  • 6
  • 51
  • 81
  • thanks for reply but if the attributed string is like this @"12345678" and out of this 2 and 3 characters are bold, 5 and 6 are italic and others are normal then how to find that ? – Sam Apr 18 '14 at 11:36
  • Look at the `NSDictionary attributes`, and at `NSRange range`. – Larme Apr 18 '14 at 11:41
  • i am doing all this just because i need to convert all the font in HelveticaNeue from calibri without changing the attributes in the attributed string. – Sam Apr 18 '14 at 11:49
  • Your answer is perfect. thanks. just one thing i would like to ask. if i dont knew the name of the font family like if i'll get the response from mail and the text will come in HTML and i'll convert it to attribute string then what to put in [[currentFont fontName] isEqualToString:@"what to put ?"]. how to find current font family and bold and italic. thanks for reply – Sam Apr 18 '14 at 12:15
  • 1
    and also if there is no old font family then ? because some time some mail will not use any font family so what should i compare in that case ? at that time the whole code will not work. – Sam Apr 18 '14 at 12:29
  • I updated my answer by giving tips/ideas to check. I didn't write actual code, but instead give you according to my experience all the cases you may encounter and giving explanations of why, and how to manage it. – Larme Apr 18 '14 at 13:32
  • your answer is really helpful and deep. you have really good knowledge of this. in all the cases you gave is true and i shall think on it and shall do it as per requirement. i am doing the MSWord's copy in iphone. but can manage from mail too. and some browser and mail send some weird HTML. at that time they are just providing or tag and no font family. i did the exact thing with some changes and it works too but the tag like above will not convert the text in to bold and in italic. you gave enough help so if you have any idea then say otherwise i'll find it and let you know here. – Sam Apr 19 '14 at 05:01