将属性字符串转换为“简单”标记的html

前端之家收集整理的这篇文章主要介绍了将属性字符串转换为“简单”标记的html前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我想将NSAttributedString转换为html,如下所示:
This is a <i>string</i> with some <b>simple</b> <i><b>html</b></i> tags in it.

不幸的是,如果你使用apple的内置系统,它会生成详细的基于CSS的html. (以下示例供参考.)

那么如何从NSAttributedString生成简单的标记html?

我写了一篇非常冗长,脆弱的电话来做这件事,这是一个糟糕的解决方案.

func simpleTagStyle(fromNSAttributedString att: NSAttributedString)->String {

    // verbose,fragile solution

    // essentially,iterate all the attribute ranges in the attString
    // make a note of what style they are,bold italic etc
    // (totally ignore any not of interest to us)
    // then basically get the plain string,and munge it for those ranges.
    // be careful with the annoying "multiple attribute" case
    // (an alternative would be to repeatedly munge out attributed ranges
    // one by one until there are none left.)

    let rangeAll = NSRange(location: 0,length: att.length)

    // make a note of all of the ranges of bold/italic
    // (use a tuple to remember which is which)
    var allBlocks: [(NSRange,String)] = []

    att.enumerateAttribute(
        NSFontAttributeName,in: rangeAll,options: .longestEffectiveRangeNotrequired
        )
            { value,range,stop in

            handler: if let font = value as? UIFont {

                let b = font.fontDescriptor.symbolicTraits.contains(.traitBold)
                let i = font.fontDescriptor.symbolicTraits.contains(.traitItalic)

                if b && i {
                    allBlocks.append( (range,"bolditalic") )
                    break handler   // take care not to duplicate
                }

                if b {
                    allBlocks.append( (range,"bold") )
                    break handler
                }

                if i {
                    allBlocks.append( (range,"italic") )
                    break handler
                }
            }

        }

    // traverse those backwards and munge away

    var plainString = att.string

    for oneBlock in allBlocks.reversed() {

        let r = oneBlock.0.range(for: plainString)!

        let w = plainString.substring(with: r)

        if oneBlock.1 == "bolditalic" {
            plainString.replaceSubrange(r,with: "<b><i>" + w + "</i></b>")
        }

        if oneBlock.1 == "bold" {
            plainString.replaceSubrange(r,with: "<b>" + w + "</b>")
        }

        if oneBlock.1 == "italic" {
            plainString.replaceSubrange(r,with: "<i>" + w + "</i>")
        }

    }

    return plainString
}

所以这里是如何使用Apple的内置系统,遗憾的是它可以生成完整的CSS等.

x = ... your NSAttributedText
var resultHtmlText = ""
do {

    let r = NSRange(location: 0,length: x.length)
    let att = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]

    let d = try x.data(from: r,documentAttributes: att)

    if let h = String(data: d,encoding: .utf8) {
        resultHtmlText = h
    }
}
catch {
    print("utterly Failed to convert to html!!! \n>\(x)<\n")
}
print(resultHtmlText)

示例输出….

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<Meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<Meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<Meta name="Generator" content="Cocoa HTML Writer">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px 'Some Font'}
span.s1 {font-family: 'SomeFont-ItalicOrWhatever'; font-weight: normal; font-style: normal; font-size: 14.00pt}
span.s2 {font-family: 'SomeFont-SemiboldItalic'; font-weight: bold; font-style: italic; font-size: 14.00pt}
</style>
</head>
<body>
<p class="p1"><span class="s1">So,</span><span class="s2">here is</span><span class="s1"> some</span> stuff</p>
</body>
</html>

解决方法

根据 enumerateAttribute:inRange:options:usingBlock:的文档,特别是讨论部分,其中指出:

If this method is sent to an instance of NSMutableAttributedString,
mutation (deletion,addition,or change) is allowed,as long as it is
within the range provided to the block; after a mutation,the
enumeration continues with the range immediately following the
processed range,after the length of the processed range is adjusted
for the mutation. (The enumerator basically assumes any change in
length occurs in the specified range.) For example,if block is called
with a range starting at location N,and the block deletes all the
characters in the supplied range,the next call will also pass N as
the index of the range.

换句话说,在闭包/块中,使用范围,您可以删除/替换那里的字符.操作系统会在该范围的末端放置一个标记.完成修改后,它将计算标记新范围,以便枚举的下一次迭代将从该新标记开始.
因此,您不必将所有范围保留在数组中,然后通过执行向后替换来应用更改,而不是修改范围.不要打扰你,方法已经做到了.

我不是Swift开发者,我更像是Objective-C开发者.所以我的Swift代码可能不会尊重所有“Swift规则”,并且可能有点丑陋(可选,包装,等等做得很糟,如果不这样做,等等)

这是我的解决方案:

func attrStrSimpleTag() -> Void {

    let htmlStr = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"> <html> <head> <Meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"> <Meta http-equiv=\"Content-Style-Type\" content=\"text/css\"> <title></title> <Meta name=\"Generator\" content=\"Cocoa HTML Writer\"> <style type=\"text/css\"> p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px 'Some Font'} span.s1 {font-family: 'SomeFont-ItalicOrWhatever'; font-weight: normal; font-style: normal; font-size: 14.00pt} span.s2 {font-family: 'SomeFont-SemiboldItalic'; font-weight: bold; font-style: italic; font-size: 14.00pt} </style> </head> <body> <p class=\"p1\"><span class=\"s1\">So,</span><span class=\"s2\">here is</span><span class=\"s1\"> some</span> stuff</p> </body></html>"
    let attr = try! NSMutableAttributedString.init(data: htmlStr.data(using: .utf8)!,options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],documentAttributes: nil)
    print("Attr: \(attr)")
    attr.enumerateAttribute(NSFontAttributeName,in: NSRange.init(location: 0,length: attr.length),options: []) { (value,stop) in
        if let font = value as? UIFont {
            print("font found:\(font)")
            let isBold = font.fontDescriptor.symbolicTraits.contains(.traitBold)
            let isItalic = font.fontDescriptor.symbolicTraits.contains(.traitItalic)
            let occurence = attr.attributedSubstring(from: range).string
            let replacement = self.formattedString(initialString: occurence,bold: isBold,italic: isItalic)
            attr.replaceCharacters(in: range,with: replacement)
        }
    };

    let taggedString = attr.string
    print("taggedString: \(taggedString)")

}

func formattedString(initialString:String,bold: Bool,italic: Bool) -> String {
    var retString = initialString
    if bold {
        retString = "<b>".appending(retString)
        retString.append("</b>")
    }
    if italic
    {
        retString = "<i>".appending(retString)
        retString.append("</i>")
    }

    return retString
}

输出(对于最后一个,其他两个打印仅用于调试):

$> taggedString: So,<i><b>here is</b></i> some stuff

编辑:
Objective-C版本(快速编写,可能是一些问题).

-(void)attrStrSimpleTag
{
    NSString *htmlStr = @"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"> <html> <head> <Meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"> <Meta http-equiv=\"Content-Style-Type\" content=\"text/css\"> <title></title> <Meta name=\"Generator\" content=\"Cocoa HTML Writer\"> <style type=\"text/css\"> p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px 'Some Font'} span.s1 {font-family: 'SomeFont-ItalicOrWhatever'; font-weight: normal; font-style: normal; font-size: 14.00pt} span.s2 {font-family: 'SomeFont-SemiboldItalic'; font-weight: bold; font-style: italic; font-size: 14.00pt} </style> </head> <body> <p class=\"p1\"><span class=\"s1\">So,</span><span class=\"s2\">here is</span><span class=\"s1\"> some</span> stuff</p> </body></html>";
    NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithData:[htmlStr dataUsingEncoding:NSUTF8StringEncoding]
                                                                              options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType}
                                                                   documentAttributes:nil
                                                                                error:nil];
    NSLog(@"Attr: %@",attr);

    [attr enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0,[attr length]) options:0 usingBlock:^(id  _Nullable value,NSRange range,BOOL * _Nonnull stop) {
        UIFont *font = (UIFont *)value;
        NSLog(@"Font found: %@",font);
        BOOL isBold =  UIFontDescriptorTraitBold & [[font fontDescriptor] symbolicTraits];
        BOOL isItalic =  UIFontDescriptorTraitItalic & [[font fontDescriptor] symbolicTraits];
        NSString *occurence = [[attr attributedSubstringFromRange:range] string];
        NSString *replacement = [self formattedStringWithString:occurence isBold:isBold andItalic:isItalic];
        [attr replaceCharactersInRange:range withString:replacement];
    }];

    NSString *taggedString = [attr string];
    NSLog(@"taggedString: %@",taggedString);
}


-(NSString *)formattedStringWithString:(NSString *)string isBold:(BOOL)isBold andItalic:(BOOL)isItalic
{
    NSString *retString = string;
    if (isBold)
    {
        retString = [NSString stringWithFormat:@"<b>%@</b>",retString];
    }
    if (isItalic)
    {
        retString = [NSString stringWithFormat:@"<i>%@</i>",retString];
    }
    return retString;
}

猜你在找的HTML相关文章