How to convert string to utf-8 in swift ? [duplicate] - character-encoding

I've a some text from json file. In this text I've applied UTF8 encode but this encoder don't recognize a non standard character àèìòù and it's capital char, is there a method to purify my string?
My function:
func stringToUTF8String (stringaDaConvertire stringa: String) -> String {
let encodedData = stringa.dataUsingEncoding(NSUTF8StringEncoding)!
let attributedOptions = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
let attributedString = NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil, error: nil)!
//println(attributedString.string)
return attributedString.string
}

I've found a solution.
The UTF8 take 8 bit of table ASCII, and the UTF16 take 16 bit ASCII table, the solution is simple by modifying my function to:
func stringToUTF16String (stringaDaConvertire stringa: String) -> String {
let encodedData = stringa.dataUsingEncoding(NSUTF16StringEncoding)!
let attributedOptions = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
let attributedString = NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil, error: nil)!
//println(attributedString.string)
return attributedString.string
}

Related

NSAttributedString Swift 4 [duplicate]

I found this string extension somewhere on SO that allows me to turn html code into an attributed string:
func html2AttributedString() -> NSAttributedString {
return try! NSAttributedString(data: self.data(using: String.Encoding.unicode, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
}
It worked fine in Swift 3, but with Swift 4, Xcode complains:
Cannot convert value of type 'NSAttributedString.DocumentAttributeKey' to expected dictionary key type 'NSAttributedString.DocumentReadingOptionKey'
How do I fix this?
You need to pass one of the available NSAttributedString DocumentType options:
Hypertext Markup Language (HTML) document.
static let html: NSAttributedString.DocumentType
Plain text document.
static let plain: NSAttributedString.DocumentType
Rich text format document.
static let rtf: NSAttributedString.DocumentType
Rich text format with attachments document.
static let rtfd: NSAttributedString.DocumentType
In this case you will need to pass the first one (html) NSAttributedString.DocumentType.html
So the extension updated to Swift 4 should look like this:
extension NSAttributedString {
convenience init(data: Data, documentType: DocumentType, encoding: String.Encoding = .utf8) throws {
try self.init(data: data,
options: [.documentType: documentType,
.characterEncoding: encoding.rawValue],
documentAttributes: nil)
}
convenience init(html data: Data) throws {
try self.init(data: data, documentType: .html)
}
convenience init(txt data: Data) throws {
try self.init(data: data, documentType: .plain)
}
convenience init(rtf data: Data) throws {
try self.init(data: data, documentType: .rtf)
}
convenience init(rtfd data: Data) throws {
try self.init(data: data, documentType: .rtfd)
}
}
extension StringProtocol {
var data: Data { return Data(utf8) }
var htmlToAttributedString: NSAttributedString? {
do {
return try .init(html: data)
} catch {
print("html error:", error)
return nil
}
}
var htmlDataToString: String? {
return htmlToAttributedString?.string
}
}
extension Data {
var htmlToAttributedString: NSAttributedString? {
do {
return try .init(html: self)
} catch {
print("html error:", error)
return nil
}
}
}
Playground Testing
let htmlString = "<style type=\"text/css\">#red{color:#F00}#green{color:#0F0}#blue{color: #00F; font-weight: Bold; font-size: 32}</style><span id=\"red\" >Red</span><span id=\"green\" > Green </span><span id=\"blue\">Blue</span>"
let htmlData = Data(htmlString.utf8)
htmlString.htmlToAttributedString
htmlData.htmlToAttributedString
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
Had this after automatic conversion to Swift 4. Was fixed by changing from:
NSMutableAttributedString(data: data,
options: [NSAttributedString.DocumentAttributeKey.documentType : NSAttributedString.DocumentType.html],
documentAttributes: nil)
to:
NSMutableAttributedString(data: data,
options: [.documentType : NSAttributedString.DocumentType.html],
documentAttributes: nil) {
This works for me:
let attrStr = try! NSAttributedString(
data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!,
options:[.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue],
documentAttributes: nil)
If you don’t add
.characterEncoding: String.Encoding.utf8.rawValue
the app will crash.
swift 4 : I dont know why all the answers have compiler error for me. so use this extension:
extension String {
var html2AttributedString: NSAttributedString? {
do {
return try NSAttributedString(data: data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!,
options: [.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue],
documentAttributes: nil)
} catch {
print("error: ", error)
return nil
}
}
var html2String: String {
return html2AttributedString?.string ?? ""
}
}
how to use ?
mylable.text = htmlVariable.html2String
For HTML string, NSAttributedString.DocumentType.html is the correct option.
Swift 4
extension String {
var utfData: Data? {
return self.data(using: .utf8)
}
var htmlAttributedString: NSAttributedString? {
guard let data = self.utfData else {
return nil
}
do {
return try NSAttributedString(data: data,
options: [
NSAttributedString.documentType: NSAttributedString.DocumentType.html,
NSAttributedString.characterEncoding: String.Encoding.utf8.rawValue
], documentAttributes: nil)
} catch {
print(error.localizedDescription)
return nil
}
}
}
Use NSAttributedString.DocumentType.html
NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html] , documentAttributes: nil)
I use NSAttributedStringKey and had similar error "Cannot convert value of type" on Swift 4. In case anyone using NSAttributedStringKey comes here looking for an answer, this is how I fixed:
let TextStroke: [NSAttributedStringKey : Any] = [
NSAttributedStringKey(rawValue: NSAttributedStringKey.strokeColor.rawValue) : UIColor.black,
NSAttributedStringKey(rawValue: NSAttributedStringKey.foregroundColor.rawValue) : UIColor.white,
NSAttributedStringKey(rawValue: NSAttributedStringKey.strokeWidth.rawValue) : -6.0,]
And this is how I add the attribute to the text:
myLabel.attributedText = NSAttributedString(string: myString, attributes: TextStroke)
Swift 4.x & 5.x
if let rtfPath = Bundle.main.url(forResource: "FileName", withExtension: "rtf") {
do {
let attributedString: NSAttributedString = try NSAttributedString(url: rtfPath, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil)
debugPrint(attributedString)
} catch {
print("Error while reading the file - \(error.localizedDescription)")
}
}
Getting NSAttributedString from file will be changed in Swift 3.x which is as below:
let attributedStringWithRtf: NSAttributedString = try NSAttributedString(url: rtfPath, options: [NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType], documentAttributes: nil)
all the other code same as Swift 4.x & 5.x.
For more details please read the Apple document related to the NSAttributedStringDocumentType

Cannot convert value of type NSAttributedString.DocumentAttributeKey to .DocumentReadingOptionKey

I found this string extension somewhere on SO that allows me to turn html code into an attributed string:
func html2AttributedString() -> NSAttributedString {
return try! NSAttributedString(data: self.data(using: String.Encoding.unicode, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
}
It worked fine in Swift 3, but with Swift 4, Xcode complains:
Cannot convert value of type 'NSAttributedString.DocumentAttributeKey' to expected dictionary key type 'NSAttributedString.DocumentReadingOptionKey'
How do I fix this?
You need to pass one of the available NSAttributedString DocumentType options:
Hypertext Markup Language (HTML) document.
static let html: NSAttributedString.DocumentType
Plain text document.
static let plain: NSAttributedString.DocumentType
Rich text format document.
static let rtf: NSAttributedString.DocumentType
Rich text format with attachments document.
static let rtfd: NSAttributedString.DocumentType
In this case you will need to pass the first one (html) NSAttributedString.DocumentType.html
So the extension updated to Swift 4 should look like this:
extension NSAttributedString {
convenience init(data: Data, documentType: DocumentType, encoding: String.Encoding = .utf8) throws {
try self.init(data: data,
options: [.documentType: documentType,
.characterEncoding: encoding.rawValue],
documentAttributes: nil)
}
convenience init(html data: Data) throws {
try self.init(data: data, documentType: .html)
}
convenience init(txt data: Data) throws {
try self.init(data: data, documentType: .plain)
}
convenience init(rtf data: Data) throws {
try self.init(data: data, documentType: .rtf)
}
convenience init(rtfd data: Data) throws {
try self.init(data: data, documentType: .rtfd)
}
}
extension StringProtocol {
var data: Data { return Data(utf8) }
var htmlToAttributedString: NSAttributedString? {
do {
return try .init(html: data)
} catch {
print("html error:", error)
return nil
}
}
var htmlDataToString: String? {
return htmlToAttributedString?.string
}
}
extension Data {
var htmlToAttributedString: NSAttributedString? {
do {
return try .init(html: self)
} catch {
print("html error:", error)
return nil
}
}
}
Playground Testing
let htmlString = "<style type=\"text/css\">#red{color:#F00}#green{color:#0F0}#blue{color: #00F; font-weight: Bold; font-size: 32}</style><span id=\"red\" >Red</span><span id=\"green\" > Green </span><span id=\"blue\">Blue</span>"
let htmlData = Data(htmlString.utf8)
htmlString.htmlToAttributedString
htmlData.htmlToAttributedString
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
Had this after automatic conversion to Swift 4. Was fixed by changing from:
NSMutableAttributedString(data: data,
options: [NSAttributedString.DocumentAttributeKey.documentType : NSAttributedString.DocumentType.html],
documentAttributes: nil)
to:
NSMutableAttributedString(data: data,
options: [.documentType : NSAttributedString.DocumentType.html],
documentAttributes: nil) {
This works for me:
let attrStr = try! NSAttributedString(
data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!,
options:[.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue],
documentAttributes: nil)
If you don’t add
.characterEncoding: String.Encoding.utf8.rawValue
the app will crash.
swift 4 : I dont know why all the answers have compiler error for me. so use this extension:
extension String {
var html2AttributedString: NSAttributedString? {
do {
return try NSAttributedString(data: data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!,
options: [.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue],
documentAttributes: nil)
} catch {
print("error: ", error)
return nil
}
}
var html2String: String {
return html2AttributedString?.string ?? ""
}
}
how to use ?
mylable.text = htmlVariable.html2String
For HTML string, NSAttributedString.DocumentType.html is the correct option.
Swift 4
extension String {
var utfData: Data? {
return self.data(using: .utf8)
}
var htmlAttributedString: NSAttributedString? {
guard let data = self.utfData else {
return nil
}
do {
return try NSAttributedString(data: data,
options: [
NSAttributedString.documentType: NSAttributedString.DocumentType.html,
NSAttributedString.characterEncoding: String.Encoding.utf8.rawValue
], documentAttributes: nil)
} catch {
print(error.localizedDescription)
return nil
}
}
}
Use NSAttributedString.DocumentType.html
NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html] , documentAttributes: nil)
I use NSAttributedStringKey and had similar error "Cannot convert value of type" on Swift 4. In case anyone using NSAttributedStringKey comes here looking for an answer, this is how I fixed:
let TextStroke: [NSAttributedStringKey : Any] = [
NSAttributedStringKey(rawValue: NSAttributedStringKey.strokeColor.rawValue) : UIColor.black,
NSAttributedStringKey(rawValue: NSAttributedStringKey.foregroundColor.rawValue) : UIColor.white,
NSAttributedStringKey(rawValue: NSAttributedStringKey.strokeWidth.rawValue) : -6.0,]
And this is how I add the attribute to the text:
myLabel.attributedText = NSAttributedString(string: myString, attributes: TextStroke)
Swift 4.x & 5.x
if let rtfPath = Bundle.main.url(forResource: "FileName", withExtension: "rtf") {
do {
let attributedString: NSAttributedString = try NSAttributedString(url: rtfPath, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil)
debugPrint(attributedString)
} catch {
print("Error while reading the file - \(error.localizedDescription)")
}
}
Getting NSAttributedString from file will be changed in Swift 3.x which is as below:
let attributedStringWithRtf: NSAttributedString = try NSAttributedString(url: rtfPath, options: [NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType], documentAttributes: nil)
all the other code same as Swift 4.x & 5.x.
For more details please read the Apple document related to the NSAttributedStringDocumentType

Convert extension to function of class

I have extension to convert html symbols to string:
extension String {
func convertHtmlSymbols() throws -> String? {
guard let data = data(using: .utf8) else { return nil }
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil).string
}
}
This extension works good. But I need convert this extension to function in class "Converter":
class Converter{
func convertHtmlSymbols(data: String) throws -> String? {
guard let data = data(using: .utf8) else { return nil }
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil).string
}
}
But I got this error:
error: Cannot call value of non-function type
In the String extension method,
guard let data = data(using: .utf8)
is a shortcut for
guard let data = self.data(using: .utf8)
i.e. the data(using:) method is called on self. In your class
you want to call it on the given string parameter (which also happens
to be called "data"), therefore it has to be
guard let data = data.data(using: .utf8)
Renaming the parameter can reduce the confusion!
As Martin R Suggested:
class Converter{
func convertHtmlSymbols(input: String) throws -> String? {
guard let data = input.data(using: .utf8) else { return nil }
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil).string
}
}
The reason is
func data(using encoding: String.Encoding, allowLossyConversion: Bool = default) -> Data?
is a method used on Strings, in your String extension it is member of the String so it knows what to do with it, but in your Converter class it's not a member/property so it doesn't see it and can't use it.
See Apple Doc
I would do it like this:
class Converter{
static func convertHtmlSymbols(_ string: String) throws -> String? {
guard let data = string.data(using: .utf8) else { return nil }
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil).string
}
}
And than call it like this:
try Converter.convertHtmlSymbols("your string here")
Try this:
class Converter{
func convertHtmlSymbols(data: String) throws -> String? {
return try? NSAttributedString(data: data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType], documentAttributes: nil).string
}
}

Cannot invoke initializer for type 'NSAttributedString' with an argument list of type [duplicate]

This question already has answers here:
Convert HTML to Plain Text in Swift
(8 answers)
Closed 7 years ago.
i followed this example to decode HTML values. TO decode a json parsed value: answered by akashivskyy
I had this code and I am getting following error:
let encodedString = "The Weeknd ‘King Of The Fall’"
let encodedData = encodedString.dataUsingEncoding(NSUTF8StringEncoding)!
let attributedOptions : [String: AnyObject] = [
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding
]
let attributedString = NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil, error: nil)!
let decodedString = attributedString.string
Error:
Cannot invoke initializer for type 'NSAttributedString' with an argument list of type '(data: NSData, options: [String : AnyObject], documentAttributes: _, error: _)'
Any help is appreciated to suggest ay answer.
Remove the error option from the NSAttributedString initializer and add the try instead:
let attributedString = try? NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil)

Display HTML string in UITextView

I am trying to display an HTML string in UITextView. Here is the key line:
self.postPage.attributedText = NSAttributedString(string: myHTMLString)
The problem I saw is that the <div> tags <img> tags are still showing... is there anything I am doing wrong?
extension String {
var html2String:String {
return NSAttributedString(data: dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil, error: nil)!.string
}
}
"<div>Testing<br></div><img src=\"http://....\">".html2String // "Testing\n"
Need to add try! if you use Xcode 7.0.1.
extension String {
var html2String:String {
return try! NSAttributedString(data: dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil).string
}
}
This function will convert all the HTML tags into NSAttributedString.
extension String{
func convertHtml() -> NSAttributedString{
guard let data = data(using: .utf8) else { return NSAttributedString() }
do{
return try NSAttributedString(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
}catch{
return NSAttributedString()
}
}
}
Usage is like:
yourTextView.attributedText = yourHtmlString.convertHtml()

Resources