在Swift中将HTML转换为纯文本

78

作为一个初学者项目,我正在使用Xcode开发一个简单的RSS阅读器应用程序。当前,我已经设置了它可以解析Feed,并在WebView中显示标题,发布日期,描述和内容。

最近,我决定在用于选择文章的TableView中显示描述(或内容的缩略版本)。 然而,在这样做时:

cell.textLabel?.text = item.title?.uppercaseString
cell.detailTextLabel?.text = item.itemDescription //.itemDescription is a String

它显示文章的原始HTML代码。

我想知道如何将HTML转换为纯文本,只用于TableView的详细UILabel中。

谢谢!

9个回答

250
您可以添加此扩展程序,将您的HTML代码转换为常规字符串:
编辑/更新:
引用: “讨论:HTML导入程序不应该从后台线程(即,选项字典包括documentType值为html)中调用。它将尝试与主线程同步,失败并超时。从主线程调用它可以工作(但如果HTML包含对外部资源的引用,则仍可能超时,这应该尽量避免)。HTML导入机制用于实现类似Markdown的内容(即文本样式、颜色等),而不是用于一般的HTML导入。”
Xcode 11.4 • Swift 5.2
extension Data {
    var html2AttributedString: NSAttributedString? {
        do {
            return try NSAttributedString(data: self, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
        } catch {
            print("error:", error)
            return  nil
        }
    }
    var html2String: String { html2AttributedString?.string ?? "" }
}

extension StringProtocol {
    var html2AttributedString: NSAttributedString? {
        Data(utf8).html2AttributedString
    }
    var html2String: String {
        html2AttributedString?.string ?? ""
    }
}

cell.detailTextLabel?.text = item.itemDescription.html2String

23
这种方法需要很高的处理器负担。 - inni
1
+1 for Swift 3:默认情况下,Xcode通过将NSUTF8StringEncoding转换为String.Encoding.utf8来移植我的Swift 2代码,但它一直崩溃。感谢这个答案,我能够通过在Encoding枚举中添加.rawValue来修复它。 - kabiroberai
1
无法在Swift 4上编译 - Hemant Singh
1
这段代码在iOS 10上运行良好,但在iOS 11上,它对HTML数据做了一些奇怪的事情,比如忽略自定义字体的字重(除非显式定义)。 - Gustavo_fringe
1
@LeoDabus 我认为这是Playgrounds的一些不稳定性问题。关闭Xcode并重新启动解决了我第一次遇到的错误。 - Adrian
显示剩余17条评论

7

Swift 4, Xcode 9

extension String {
    
    var utfData: Data {
        return Data(utf8)
    }
    
    var attributedHtmlString: NSAttributedString? {
        
        do {
            return try NSAttributedString(data: utfData, options: [
              .documentType: NSAttributedString.DocumentType.html,
              .characterEncoding: String.Encoding.utf8.rawValue
            ], 
            documentAttributes: nil)
        } catch {
            print("Error:", error)
            return nil
        }
    }
}

extension UILabel {
   func setAttributedHtmlText(_ html: String) {
      if let attributedText = html.attributedHtmlString {
         self.attributedText = attributedText
      } 
   }
}

任何字符串都可以转换为 utf8 数据。返回可选项是无意义的。只需 return Data(utf8) - Leo Dabus
在这里,我们希望将字符串转换为NSAttributedString,为什么只返回Data(utf8)会很有用呢? - Suhit Patil
我是指 var utf8data: Data { return Data(utf8) },并且从你的方法中移除 guard。 - Leo Dabus
顺便提一下,localizedDescription 是冗余的。只需要 print(error) 即可。 - Leo Dabus

3

这是我的建议回答。如果您想将其放在函数中,而不是扩展名。

func decodeString(encodedString:String) -> NSAttributedString?
    {
        let encodedData = encodedString.dataUsingEncoding(NSUTF8StringEncoding)!
        do {
            return try NSAttributedString(data: encodedData, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil)
        } catch let error as NSError {
            print(error.localizedDescription)
            return nil
        }
    }

调用该函数并将NSAttributedString强制转换为String类型

let attributedString = self.decodeString(encodedString)
let message = attributedString.string

2

Swift4.0 扩展

 extension String {
    var html2AttributedString: String? {
    guard let data = data(using: .utf8) else { return nil }
    do {
        return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil).string

    } catch let error as NSError {
        print(error.localizedDescription)
        return  nil
    }
  }
}

1
请使用以下代码测试detailTextLabel的详细信息:
var attrStr = NSAttributedString(
        data: item.itemDescription.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true),
        options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
        documentAttributes: nil,
        error: nil)
cell.detailTextLabel?.text = attrStr

嗨@AltimirAntonov,感谢您的回复。item.itemDescription是一个字符串 - 也许我之前应该澄清一下。我应该将它转换为NSData吗? - Zaid Syed

1
尝试在 Swift 3 中使用此解决方案。
extension String{
    func convertHtml() -> NSAttributedString{
        guard let data = data(using: .utf8) else { return NSAttributedString() }
        do{
            return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
        }catch{
            return NSAttributedString()
        }
    }
}

使用方法

self.lblValDesc.attributedText = str_postdescription.convertHtml()

0
我使用了Danboz的答案,只是将其更改为返回一个简单的字符串(而不是富文本字符串):
static func htmlToText(encodedString:String) -> String?
{
    let encodedData = encodedString.dataUsingEncoding(NSUTF8StringEncoding)!
    do
    {
        return try NSAttributedString(data: encodedData, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil).string
    } catch let error as NSError {
        print(error.localizedDescription)
        return nil
    }
}

对我来说,它像魔法一样运作良好,谢谢Danboz


0

Swift 5.*

这里是基于字符串扩展的简洁解决方案:

import UIKit

extension String {
    var attributedHtmlString: NSAttributedString? {
        try? NSAttributedString(
            data: Data(utf8),
            options: [
                .documentType: NSAttributedString.DocumentType.html,
                .characterEncoding: String.Encoding.utf8.rawValue
            ],
            documentAttributes: nil
        )
    }
}

使用方法:

let html = "hello <br><br/> <b>world</b>"
if let attributedText = html.attributedHtmlString {
    print(attributedText.string) // "hello \n\nworld\n"
}

你也可以根据你的需求保留属性字符串


0
let content = givenString // html included string
let attrStr = try! NSAttributedString(data: content.data(using: String.Encoding.unicode, allowLossyConversion: true)!,options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],documentAttributes: nil)
self.labelName.attributedText = attrStr    

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