HTML 到 NSAttributedString 和 NSAttributedString 到 HTML

HTML to NSAttributedString and NSAttributedString to HTML

我想将 html 字符串转换为 NSAttributedString 然后处理字符串(更改颜色、字体大小、字体系列、背景-、前景色。 ..) 然后将字符串从 NSAttributedString.

转换回纯 html

转换 不是问题,但每次我将 html 转换为 NSAS 并返回 fontsize越来越大...

游乐场示例:

// Playground - noun: a place where people can play
// NSAS: - NSAttributedString

import UIKit

class Wrapper {

    //MARK: fields
    let apiHtml = "<div style='font-size: 18px'><span style='font-family:&#039;andale mono&#039;, times;'>Dies</span> <span style='font-family:&#039;comic sans ms&#039;, sans-serif;'>ist</span> <strong><span style='font-family:&#039;andale mono&#039;, sans-serif;';>eine</span></strong> <em>formatierte</em> <span style='text-decoration:underline;'>Karte</span>&#160;<span style='font-size:16px;'>die</span> <span style='background-color:#ffff00;'>es</span> zu &#220;bernehmen gilt</div>"

    var newGeneratedHtml = ""
    var textView : UITextView!

    //MARK: constructor
    init() {
        //init textview
        textView = UITextView(frame: CGRectMake(0, 0, 500, 300))

        //convert html into NSAS and set it to textview
        if let attributedText = getAttributedTextFromApiHtmlString(apiHtml) {
            textView.attributedText = attributedText
        }

        //get html text from textfields NSAS
        if let htmlText = getHtmlTextFromTextView() {
            newGeneratedHtml = htmlText
            println(htmlText)
        }

        //set the converted html from textfields NSAS
        if let attributedText = getAttributedTextFromApiHtmlString(newGeneratedHtml) {
            textView.attributedText = attributedText
        }

        //get html text from textfields NSAS
        if let htmlText = getHtmlTextFromTextView() {
            newGeneratedHtml = htmlText
            println(htmlText)
        }
    }

    //MARK: methods
    func getAttributedTextFromApiHtmlString(text : String) -> NSAttributedString? {
        if let attributedText = NSAttributedString(data: text.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType], documentAttributes: nil, error: nil) {
            return attributedText
        }
        return nil
    }

    func getHtmlTextFromTextView() -> String? {
        let attributedTextFromTextView = textView.attributedText
        if let htmlData = attributedTextFromTextView.dataFromRange(NSMakeRange(0, attributedTextFromTextView.length), documentAttributes: [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType], error: nil) {
            if let htmlString = NSString(data: htmlData, encoding: NSUTF8StringEncoding) {
                return htmlString
            }
        }
        return nil
    }
}

var w = Wrapper()

这是游乐场的结果。你可以看到第二个文本比第一个文本大,但我没有改变任何地方的字体大小。

这是错误还是我必须设置固定字体大小?

更新:

我接受@Lou Franco 的回答。我不知道为什么 NSAS 将 px 转换为 pt 并返回,但这是我的解决方法:

func getAttributedTextFromApiHtmlString(text : String) -> NSAttributedString? {
        if let attributedText = NSAttributedString(data: text.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, options: [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType], documentAttributes: nil, error: nil) {

            var res : NSMutableAttributedString = attributedText.mutableCopy() as NSMutableAttributedString
            res.beginEditing()
            var found : Bool = false;
            res.enumerateAttribute(NSFontAttributeName, inRange:NSMakeRange(0, res.length) ,options:NSAttributedStringEnumerationOptions.allZeros, usingBlock: {(value:AnyObject!, range:NSRange, stop:UnsafeMutablePointer<ObjCBool>) -> Void in
                if ((value) != nil) {
                    let oldFont = value as UIFont;
                    let newFont = oldFont.fontWithSize(15)
                    res.removeAttribute(NSFontAttributeName, range:range)
                    res.addAttribute(NSFontAttributeName, value: newFont, range: range)
                    found = true
                    }
                })
            if !found {
                // No font was found - do something else?
            }
            res.endEditing()
            return res
        }
        return nil
    }

这样做的唯一缺点是您 失去了 在您的 NSAS 中不同的文本高度....

如果有人有解决方案或更好的解决方法,请随时 post 您的回答。

可能是往返的舍入误差。尝试使用整数点大小(使用 pt 而不是 px

好的,看看你的控制台输出,它正在将你的 px 翻译成 pt,所以也许你可以通过获取来自转换的 HTML 并改变 pt 回到 px

我通过对字符串中的每个喜欢大小应用 0.75 比率来解决这个问题。假设您的属性字符串中有多种字体,当您循环遍历所有字体时,只需应用比率,然后就可以了。这是我在 swift 3.0 中的代码:

yourAttrStr.beginEditing()
yourAttrStr.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, yourAttrStr.length), options: .init(rawValue: 0)) { 
        (value, range, stop) in
        if let font = value as? UIFont {
            let resizedFont = font.withSize(font.pointSize * 0.75)
            yourAttrStr.addAttribute(NSFontAttributeName, value: resizedFont, range: range)
        }
}
yourAttrStr.endEditing()//yourAttrStr will be the same size as html string

这是我的应用程序中运行的一段代码

extension String {
    func htmlAttributedString() -> NSAttributedString? {
        guard let data = self.data(using: String.Encoding.utf16, allowLossyConversion: false) else { return nil }
        guard let html = try? NSMutableAttributedString(
            data: data,
            options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
            documentAttributes: nil) else { return nil }
        html.beginEditing()
        html.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, html.length), options: .init(rawValue: 0)) {
            (value, range, stop) in
            if let font = value as? UIFont {
                let resizedFont = font.withSize(font.pointSize * 0.75)
                html.addAttribute(NSFontAttributeName,
                                         value: resizedFont,
                                         range: range)
            }
        }
        html.endEditing()
        return html
    }
}

使用方法:

let htmlStr: String = "<font size=\"6\">font a</font><font size=\"16\">Font b</font>"
let attriStr: NSAttributedString? = htmlStr.htmlAttributedString()

在 Swift 3 中采用@fangming 的解决方案,对我有用:

func newAttrSize(blockQuote: NSAttributedString) -> NSAttributedString
{
    let yourAttrStr = NSMutableAttributedString(attributedString: blockQuote)
    yourAttrStr.enumerateAttribute(.font, in: NSMakeRange(0, yourAttrStr.length), options: .init(rawValue: 0)) {
        (value, range, stop) in
        if let font = value as? UIFont {
            let resizedFont = font.withSize(font.pointSize * 0.75)
            yourAttrStr.addAttribute(.font, value: resizedFont, range: range)
        }
    }

    return yourAttrStr
}