将属性字符串转换为“简单”标记的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: 的文档,特别是讨论部分,其中指出:
换句话说,在闭包/块中,使用范围,您可以删除/替换那里的字符.操作系统会在该范围的末端放置一个标记.完成修改后,它将计算标记新范围,以便枚举的下一次迭代将从该新标记开始. 我不是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 编辑: -(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; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |