79

I'm working on a simple RSS Reader app as a beginner project in Xcode. I currently have it set up that it parses the feed, and places the title, pub date, description and content and displays it in a WebView.

I recently decided to show the description (or a truncated version of the content) in the TableView used to select a post. However, when doing so:

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

It shows the raw HTML of the post.

I would like to know how to convert the HTML into plain text for just the TableView's detailed UILabel.

Thanks!

0

9 Answers 9

252

You can add this extension to convert your html code to a regular string:

edit/update:

Discussion The HTML importer should not be called from a background thread (that is, the options dictionary includes documentType with a value of html). It will try to synchronize with the main thread, fail, and time out. Calling it from the main thread works (but can still time out if the HTML contains references to external resources, which should be avoided at all costs). The HTML import mechanism is meant for implementing something like markdown (that is, text styles, colors, and so on), not for general HTML import.

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 
Sign up to request clarification or add additional context in comments.

22 Comments

this method is very processor heavy
+1 for Swift 3: by default, Xcode ported my code from Swift 2 by converting NSUTF8StringEncoding into String.Encoding.utf8, but it kept crashing. Thanks to this answer, I was able to fix it by appending .rawValue to the Encoding enum.
doesn't compile on swift 4
This works fine on ios 10, but on ios 11 it does some weird things with the html data like it ignores the the font weight of a custom font. unless explicitly defined.
@LeoDabus I think it was some flakiness in Playgrounds. Closing Xcode and restarting resolved the error I encountered the first time.
|
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 } } } 

4 Comments

ANY string can be converted to utf8 data. Returning optional is pointless. Just return Data(utf8)
Here we want string to be converted in NSAttributedString, why returning just Data(utf8) would be useful?
I meant var utf8data: Data { return Data(utf8) } and remove the guard from your method
Btw localizedDescription is redundant. Just print(error)
3

Here is my suggested answer. Instead of extension, if you want to put inside function.

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 } } 

And call that function and cast NSAttributedString to String

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

Comments

2

Swift4.0 Extension

 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 } } } 

Comments

2

Swift 5.*

Here's a compact solution based on string extension:

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

Usage:

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

You can also keep the attributed string ofc, based on your necessities

Comments

1

Please test with this code for the detailTextLabel:

var attrStr = NSAttributedString( data: item.itemDescription.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true), options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil, error: nil) cell.detailTextLabel?.text = attrStr 

1 Comment

Hi @AltimirAntonov, thanks for the reply. item.itemDescription is a String - perhaps I should have clarified that earlier. Should I convert it to NSData?
1

Try this solution in swift3

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() } } } 

To use

self.lblValDesc.attributedText = str_postdescription.convertHtml() 

Comments

0

i have used Danboz answer, only changed it to return a simple String (not a rich text string):

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 } } 

for me, it works like a charm, thanks Danboz

Comments

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 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.