Objective C - 将HTML转换为NSAttributedString

4
我已经编写了一个函数,可以将HTML文本转换为NSAttributedString。它的运行良好。然而,我注意到当一些标签嵌套在另一个标签中时,它们的字体会被覆盖。
以下是我的代码:
+(NSMutableAttributedString*) replaceHTMLTags : (NSString*) text : (NSString*) fontName : (CGFloat) fontSize
{
    UIFont* font = [UIFont fontWithName:fontName size:fontSize];
    NSMutableParagraphStyle* paragraphStyle = [[NSMutableParagraphStyle alloc]init];
    paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
    paragraphStyle.alignment = NSTextAlignmentJustified;

    text = [text stringByReplacingOccurrencesOfString:@"<br>" withString:@"\n"];
    NSMutableAttributedString* finalText = [[NSMutableAttributedString alloc]initWithString:text];

    [finalText setAttributes:@{NSFontAttributeName:font} range:NSMakeRange(0, [finalText string].length)];

    finalText = [self recurseFunc:finalText :@"" : font : paragraphStyle];
    return finalText;
}

+(NSMutableAttributedString*) recurseFunc : (NSMutableAttributedString*) text : (NSString*) tag : (UIFont*) font : (NSMutableParagraphStyle*) paragraphStyle
{
    NSMutableAttributedString* finalText = text;

    NSRange newOpenTagRange;
    //RECURSE IF THERE ARE MORE TAGS
    while((newOpenTagRange = [[text string] rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
    {
        NSString* openTagName = [[text string] substringWithRange:newOpenTagRange];
        NSString* closeTagName = [self getCloseTagName: openTagName];
        NSRange newCloseTagRange = [[text string ]rangeOfString:closeTagName];

        if(newCloseTagRange.location != NSNotFound)
        {
            NSString* textWithTags = [[text string] substringWithRange:NSMakeRange(newOpenTagRange.location, newCloseTagRange.location - newOpenTagRange.location + newCloseTagRange.length)];
            NSString* newPlainText = [textWithTags stringByReplacingOccurrencesOfString:openTagName withString:@""];
            newPlainText = [newPlainText stringByReplacingOccurrencesOfString:closeTagName withString:@""];

            NSMutableAttributedString* newText = [[NSMutableAttributedString alloc]initWithString:newPlainText attributes:@{NSFontAttributeName:font,  NSParagraphStyleAttributeName:paragraphStyle}];

            newText = [self recurseFunc:newText :openTagName : font : paragraphStyle];
            [finalText replaceCharactersInRange:NSMakeRange(newOpenTagRange.location, newCloseTagRange.location - newOpenTagRange.location + newCloseTagRange.length) withAttributedString:newText];
        }
        else
        {
            NSLog(@"Cannot find closing tag for tag %@", openTagName);
        }
    }

    //FORMAT HTML TAGS
    if([tag containsString:@"<p"])
    {
        [finalText.mutableString appendString:@"\n\n"];
    }

    else if ([tag isEqualToString:@"<i>"])
    {
        UIFont* italicFont = [UIFont fontWithName:@"Arial-ItalicMT" size:DEFAULT_FONT_SIZE];
        [finalText addAttribute:NSFontAttributeName value:italicFont range:NSMakeRange(0, [finalText string].length)];
    }
    else if ([tag isEqualToString:@"<b>"])
    {
        UIFont* boldFont = [UIFont fontWithName:@"Arial-BoldMT" size:DEFAULT_FONT_SIZE];
        [finalText addAttribute:NSFontAttributeName value:boldFont range:NSMakeRange(0, [finalText string].length)];

    }
    else if([tag isEqualToString:@"<ul>"])
    {
        NSMutableParagraphStyle* tempStyle = [[NSMutableParagraphStyle alloc]init];
        tempStyle.headIndent = 30;
        tempStyle.firstLineHeadIndent = 10;
        tempStyle.lineBreakMode = NSLineBreakByWordWrapping;
        tempStyle.alignment = NSTextAlignmentJustified;

        NSString* temp = [[finalText string]stringByReplacingOccurrencesOfString:@"###" withString:@"•\t"];
        temp = [NSString stringWithFormat:@"\n%@", temp];
        [finalText setAttributedString:[[NSAttributedString alloc] initWithString:temp]];

        [finalText addAttribute:NSParagraphStyleAttributeName value:tempStyle range:NSMakeRange(0, [finalText string].length)];


    }
    else if ([tag isEqualToString:@"<li>"])
    {
        NSMutableAttributedString* tempAS = [[NSMutableAttributedString alloc]initWithString:@"###$$$\n"];
        NSRange r = [[tempAS string]rangeOfString:@"$$$"];
        [tempAS replaceCharactersInRange:r withAttributedString:finalText];
        [finalText setAttributedString:tempAS];

    }
    return finalText;
}

这段代码完全按照预期工作,但有一个特定的情况需要注意。

例如,如果我在 <ul><li> 标签内部使用了 <b><i> 标签,那么这些标签将不会被呈现出来。


没有测试过你的整个代码,但是快速查看后,我猜 <b><i>someText</i></b> 不会起作用,无法同时加粗和倾斜。 - Larme
@Larme 我已经测试了整个代码,一切都正常。问题出在这样的场景中:<ul><li>Some<b>Text</b></li></ul>。其中,“Text”没有变成粗体。然而,如果只是 <p>Some <b>Text</b></p>,它就可以正常工作。 - user2771150
1
[finalText replaceCharactersInRange:[[finalText string] rangeOfString:@"###"] withString:@"•\t"]; 替换 NSString* temp = [[finalText string]stringByReplacingOccurrencesOfString:@"###" withString:@"•\t"]; temp = [NSString stringWithFormat:@"\n%@", temp]; [finalText setAttributedString:[[NSAttributedString alloc] initWithString:temp]]; 这段代码,这样可以解决你的一个问题。 - Larme
1
你的第二个问题在这里:NSMutableAttributedString* newText = [[NSMutableAttributedString alloc]initWithString:newPlainText attributes:@{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle}]; 你正在覆盖字体,因此如果它是 “Arial-Bold”,则将被参数中的字体覆盖。 - Larme
1
你好,只有一个小问题,为什么不能使用这个解决方案 https://dev59.com/6m855IYBdhLWcg3wp2J0#18886718 ? - Aris
显示剩余3条评论
1个回答

2

要将 HTML 转换为 NSAttributedString,您可以使用以下代码:

[[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding] 
                             options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                       NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} 
                  documentAttributes:nil error:nil];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接