IOS में HTML को NSAttributedString में कनवर्ट करें


151

मैं UIWebViewकुछ पाठ को संसाधित करने और इसे सही ढंग से रंगने के लिए एक उदाहरण का उपयोग कर रहा हूं , यह HTML के रूप में परिणाम देता है, लेकिन इसे प्रदर्शित करने के बजाय UIWebViewमैं इसे Core Textएक के साथ प्रयोग करके प्रदर्शित करना चाहता हूं NSAttributedString

मैं बनाने और आकर्षित करने में सक्षम हूं, NSAttributedStringलेकिन मैं अनिश्चित हूं कि मैं HTML को कैसे जिम्मेदार स्ट्रिंग में परिवर्तित और मैप कर सकता हूं।

मैं समझता हूं कि मैक ओएस एक्स के तहत NSAttributedStringएक initWithHTML:विधि है लेकिन यह केवल मैक के अलावा था और आईओएस के लिए उपलब्ध नहीं है।

मुझे यह भी पता है कि इस पर भी कुछ ऐसा ही सवाल है, लेकिन इसका कोई जवाब नहीं था, हालांकि मैं फिर से कोशिश करूंगा और देखूंगा कि क्या किसी ने ऐसा करने का कोई तरीका बनाया है और यदि ऐसा है, तो वे इसे साझा कर सकते हैं।


2
NSAttributedString-Additions-for-HTML लाइब्रेरी का नाम बदलकर उसी लेखक द्वारा एक फ्रेमवर्क में रोल किया गया है। अब इसे DTCoreText कहा जाता है और इसमें कोर टेक्स्ट लेआउट कक्षाओं का एक समूह शामिल है। आप इसे यहां
ब्रायन डगलस मोकले

जवाबों:


290

IOS 7 में, UIKit ने एक initWithData:options:documentAttributes:error:तरीका जोड़ा है जो NSAttributedStringHTML, जैसे:

[[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding] 
                                 options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                           NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} 
                      documentAttributes:nil error:nil];

स्विफ्ट में:

let htmlData = NSString(string: details).data(using: String.Encoding.unicode.rawValue)
let options = [NSAttributedString.DocumentReadingOptionKey.documentType:
        NSAttributedString.DocumentType.html]
let attributedString = try? NSMutableAttributedString(data: htmlData ?? Data(),
                                                          options: options,
                                                          documentAttributes: nil)

28
किसी कारण से, विकल्प NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType एक सच में, सच लंबे समय :( लेने के लिए एन्कोडिंग खड़ी कर रहा है
Arie Litovsky

14
बहुत बुरा NSHTMLTextDocumentType NSRange के साथ विशेषता सेट करने की तुलना में (शाब्दिक) ~ 1000x धीमा है। (एक बोल्ड टैग के साथ एक छोटा लेबल प्रोफाइल किया गया।)
जेसन मूर

6
इस बात से अवगत रहें कि यदि आप बैकग्राउंड थ्रेड से इसका उपयोग करना चाहते हैं तो आप इस विधि से NSHTMLTextDocumentType नहीं कर सकते। आईओएस 7 के साथ भी, यह HTML प्रतिपादन के लिए TextKit का उपयोग नहीं करेगा। Ingve द्वारा अनुशंसित DTCoreText लाइब्रेरी पर एक नज़र डालें।
TJez

2
बहुत बढ़िया। बस एक विचार, आप शायद कर सकते हैं [NSNumber numberWithInt: NSUTF8StringEncoding] @ (NSUTF8StringEncoding) के रूप में, नहीं?
जार्सन

15
मैं यह कर रहा था, लेकिन आईओएस 8 पर सावधान रहें। यह कुछ सौ वर्णों के लिए एक सेकंड के करीब, दर्द से धीमा है। (IOS 7 में यह लगभग तात्कालिक था।)
नॉर्मन

43

गिथब में ओलिवर ड्रोबनिक द्वारा NSAttributedString के अलावा एक काम-में-प्रगति खुला स्रोत है । यह HTML पार्सिंग के लिए NSScanner का उपयोग करता है।


आईओएस 4.3 की न्यूनतम तैनाती की आवश्यकता है :( कोई भी कम नहीं, बहुत प्रभावशाली।
ओह डैनी बॉय

3
आपके लिए @Lirik ओवरकिल शायद किसी और के लिए परफेक्ट हो यानी आपकी टिप्पणी कम से कम मददगार न हो।
wuf810

3
कृपया ध्यान दें कि इस परियोजना के लिए खुला स्रोत है और एक मानक 2-खंड बीएसडी लाइसेंस द्वारा कवर किया गया है। इसका मतलब है कि आपको कोकोनेटिक्स का इस कोड के मूल लेखक के रूप में उल्लेख करना होगा और अपने ऐप के अंदर LICENSE पाठ को पुन: पेश करना होगा।
dulgan

28

HTML से NSAttributedString बनाना मुख्य धागे पर किया जाना चाहिए!

अद्यतन: यह पता चलता है कि NSAttributedString HTML रेंडरिंग हुड के नीचे WebKit पर निर्भर करता है, और इसे मुख्य थ्रेड पर चलाया जाना चाहिए या यह कभी-कभी किसी SIGTRAP ऐप को क्रैश कर देगा

नया अवशेष दुर्घटना लॉग:

यहाँ छवि विवरण दर्ज करें

नीचे एक अद्यतन थ्रेड-सुरक्षित स्विफ्ट 2 स्ट्रिंग एक्सटेंशन है:

extension String {
    func attributedStringFromHTML(completionBlock:NSAttributedString? ->()) {
        guard let data = dataUsingEncoding(NSUTF8StringEncoding) else {
            print("Unable to decode data from html string: \(self)")
            return completionBlock(nil)
        }

        let options = [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
                   NSCharacterEncodingDocumentAttribute: NSNumber(unsignedInteger:NSUTF8StringEncoding)]

        dispatch_async(dispatch_get_main_queue()) {
            if let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) {
                completionBlock(attributedString)
            } else {
                print("Unable to create attributed string from html string: \(self)")
                completionBlock(nil)
            }
        }
    }
}

उपयोग:

let html = "<center>Here is some <b>HTML</b></center>"
html.attributedStringFromHTML { attString in
    self.bodyLabel.attributedText = attString
}

आउटपुट:

यहाँ छवि विवरण दर्ज करें


एंड्रयू। यह ठीक काम कर रहा है। मैं यह जानना चाहता था कि अगर मैं इस दृष्टिकोण के साथ जाऊंगा तो मुझे अपने UITextView में कौन सी घटनाओं को संभालना है। क्या यह HTML में उपलब्ध कैलेंडर ईवेंट, कॉल, ईमेल, वेबसाइट लिंक आदि को संभाल सकता है? मुझे आशा है कि UITextView, UILabel की तुलना में घटनाओं को संभालने में सक्षम है।
harshit2811

उपरोक्त दृष्टिकोण केवल स्वरूपण के लिए अच्छा है। अगर आपको इवेंट हैंडलिंग की आवश्यकता है तो मैं TTTAttributedLabel का उपयोग करने की सलाह दूंगा
एंड्रयू श्रेबर

NSAFributedString का उपयोग करने वाली डिफ़ॉल्ट एन्कोडिंग NSUTF16StringEncoding (UTF8 नहीं है!)। इसलिए यह काम नहीं करेगा। कम से कम मेरे मामले में!
उमित काया

यह स्वीकृत समाधान होना चाहिए। पृष्ठभूमि थ्रेड पर HTML स्ट्रिंग वार्तालाप करना अंततः क्रैश हो जाएगा , और परीक्षण चलाते समय काफी बार।
रतिसिम्हा

21

NSAttributedString पर स्विफ्ट इनिशियलाइज़र एक्सटेंशन

मेरा झुकाव इसके NSAttributedStringबजाय एक विस्तार के रूप में जोड़ना था String। मैंने इसे स्टैटिक एक्सटेंशन और इनिशियलाइज़र के रूप में आज़माया। मैं इनिशियलाइज़र पसंद करता हूं जो कि मैंने नीचे शामिल किया है।

स्विफ्ट 4

internal convenience init?(html: String) {
    guard let data = html.data(using: String.Encoding.utf16, allowLossyConversion: false) else {
        return nil
    }

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

    self.init(attributedString: attributedString)
}

स्विफ्ट 3

extension NSAttributedString {

internal convenience init?(html: String) {
    guard let data = html.data(using: String.Encoding.utf16, allowLossyConversion: false) else {
        return nil
    }

    guard let attributedString = try? NSMutableAttributedString(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) else {
        return nil
    }

    self.init(attributedString: attributedString)
}
}

उदाहरण

let html = "<b>Hello World!</b>"
let attributedString = NSAttributedString(html: html)

मैं चाहता हूं कि हैलो वर्ल्ड इस तरह हो <p> <b> <i> हैलो </ i> </ b> <i> दुनिया </ i> </ p>
उमा माधवी

कुछ एलओसी सहेजें और की जगह guard ... NSMutableAttributedString(data:...से try self.init(data:...(और जोड़ने throwsinit करने के लिए)
nyg

और अंत में यह काम नहीं करता है - पाठ लाभ यादृच्छिक फ़ॉन्ट आकार
व्याचेस्लाव गेर्चिकोव

2
आप UTF-8 के साथ डेटा को डिकोड कर रहे हैं, लेकिन आपने इसे UTF-16 के साथ एनकोड किया है
श्याम भट्ट

11

यह Stringएचटीएमएल स्ट्रिंग को वापस करने के लिए स्विफ्ट में लिखा गया एक एक्सटेंशन है NSAttributedString

extension String {
    func htmlAttributedString() -> NSAttributedString? {
        guard let data = self.dataUsingEncoding(NSUTF16StringEncoding, allowLossyConversion: false) else { return nil }
        guard let html = try? NSMutableAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) else { return nil }
        return html
    }
}

काम में लाना,

label.attributedText = "<b>Hello</b> \u{2022} babe".htmlAttributedString()

उपर्युक्त में, मैंने जानबूझकर यूनिकोड \ u2022 जोड़ा है, यह दिखाने के लिए कि यह यूनिकोड को सही ढंग से प्रस्तुत करता है।

एक तुच्छ: डिफ़ॉल्ट एन्कोडिंग जो NSAttributedStringउपयोग करता है NSUTF16StringEncoding(UTF8 नहीं है!)।


UTF16 ने मेरा दिन बचाया, धन्यवाद samwize!
यूएयू

UTF16 ने मेरा दिन बचाया, धन्यवाद samwize!
यूएयू

6

एंड्रयू पर कुछ संशोधन किया के समाधान और कोड को स्विफ्ट 3 में अपडेट करें:

यह कोड अब UITextView का उपयोग करता है self और अपने मूल फ़ॉन्ट, फ़ॉन्ट आकार और पाठ रंग को इनहेरिट करने में सक्षम है

नोट: यहाँtoHexString() से विस्तार है

extension UITextView {
    func setAttributedStringFromHTML(_ htmlCode: String, completionBlock: @escaping (NSAttributedString?) ->()) {
        let inputText = "\(htmlCode)<style>body { font-family: '\((self.font?.fontName)!)'; font-size:\((self.font?.pointSize)!)px; color: \((self.textColor)!.toHexString()); }</style>"

        guard let data = inputText.data(using: String.Encoding.utf16) else {
            print("Unable to decode data from html string: \(self)")
            return completionBlock(nil)
        }

        DispatchQueue.main.async {
            if let attributedString = try? NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) {
                self.attributedText = attributedString
                completionBlock(attributedString)
            } else {
                print("Unable to create attributed string from html string: \(self)")
                completionBlock(nil)
            }
        }
    }
}

उदाहरण उपयोग:

mainTextView.setAttributedStringFromHTML("<i>Hello world!</i>") { _ in }

5

स्विफ्ट 3.0 Xcode 8 संस्करण

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

5

स्विफ्ट 4


  • NSAttributedString सुविधा प्रारंभ करनेवाला
  • बिना अतिरिक्त गार्ड के
  • त्रुटि फेंकता है

extension NSAttributedString {

    convenience init(htmlString html: String) throws {
        try self.init(data: Data(html.utf8), options: [
            .documentType: NSAttributedString.DocumentType.html,
            .characterEncoding: String.Encoding.utf8.rawValue
        ], documentAttributes: nil)
    }

}

प्रयोग

UILabel.attributedText = try? NSAttributedString(htmlString: "<strong>Hello</strong> World!")

तुम मेरा दिन बचाओ। धन्यवाद।
pkc456

@ pkc456 meta.stackexchange.com/questions/5234/… , upvote :) धन्यवाद!
आमिर

मैं फ़ॉन्ट आकार और फ़ॉन्ट परिवार कैसे सेट कर सकता हूं?
किर्के

यह मोबाइल डैन द्वारा सुझाए गए से बहुत बेहतर है, क्योंकि इसमें self.init के साथ निरर्थक कॉपी शामिल नहीं है (एट्रिब्यूटेड स्ट्रिंग: एट्रिब्यूटेड स्ट्रिंग)
साइनाइड

4

अभी आपके पास एकमात्र समाधान HTML को पार्स करना, दिए गए बिंदु / फ़ॉन्ट / आदि विशेषताओं के साथ कुछ नोड्स बनाना है, फिर उन्हें एक साथ NSAttributedString में संयोजित करें। यह बहुत काम है, लेकिन अगर सही तरीके से किया जाए, तो भविष्य में पुन: उपयोग किया जा सकता है।


1
यदि HTML XHTML- सख्त है, तो आप पार्सिंग की मदद करने के लिए NSXMLDOcument और दोस्तों का उपयोग कर सकते हैं।
डायलन लुकेस

आप कैसे सुझाव देंगे कि मैं दिए गए विशेषताओं के साथ नोड के निर्माण के बारे में जाऊं?
जोशुआ

2
यह एक कार्यान्वयन विवरण है। हालाँकि आप HTML को पार्स करते हैं, आपके पास प्रत्येक टैग के लिए प्रत्येक विशेषता तक पहुंच होती है, जो फ़ॉन्ट नाम, आकार आदि जैसी चीजों को निर्दिष्ट करती है। आप इस जानकारी का उपयोग उन प्रासंगिक विवरणों को संग्रहीत करने के लिए कर सकते हैं जिन्हें आपको विशेषता के रूप में जिम्मेदार पाठ में जोड़ना होगा। । आम तौर पर, आपको इस तरह के कार्य से निपटने से पहले पहले स्वयं को परिचित करने की आवश्यकता होती है।
jer

2

उपरोक्त समाधान सही है।

[[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding] 
                                 options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                           NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} 
                      documentAttributes:nil error:nil];

लेकिन अगर आप इसे ios 8.1,2 या 3 पर चला रहे हैं तो ऐप वायर क्रैश हो जाता है।

क्रैश से बचने के लिए आप क्या कर सकते हैं: इसे एक कतार में चलाएं। ताकि यह हमेशा मुख्य धागे पर हो।


@alecex मैं इसी समस्या को पूरा करता था! ऐप iOS 8.1, 2, 3 पर क्रैश हो जाएगा। लेकिन iOS 8.4 या उसके बाद का संस्करण ठीक रहेगा। क्या आप विस्तार से बता सकते हैं कि इससे कैसे बचा जाए? या आसपास कोई काम है, या इसके बजाय तरीकों का इस्तेमाल किया जा सकता है?
मजबूत

मैंने इसे संभालने के लिए एक त्वरित श्रेणी बनाई, AppKit से विधियों की प्रतिलिपि बनाना, जिसमें ऐसा करने का एक बहुत आसान और सहज तरीका है। Apple ने इसे क्यों नहीं जोड़ा यह मुझसे परे है: github.com/cguess/NSMutableAttributedString-HTML
CGuess

2

NSHTMLTextDocumentType का उपयोग धीमा है और शैलियों को नियंत्रित करना कठिन है। मैं आपको सुझाव देता हूं कि आप मेरी लाइब्रेरी को आजमाएं, जिसे एतवेनिका कहा जाता है। इसका अपना बहुत तेज़ HTML parser है। इसके अलावा, आपके पास कोई भी टैग नाम हो सकता है और उनके लिए किसी भी शैली को परिभाषित कर सकता है।

उदाहरण:

let str = "<strong>Hello</strong> World!".style(tags:
    Style("strong").font(.boldSystemFont(ofSize: 15))).attributedString

label.attributedText = str

आप इसे यहां पा सकते हैं https://github.com/psharanda/Atributika


2

स्विफ्ट 3 :
यह कोशिश करो :

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

और उपयोग करने के लिए:

let str = "<h1>Hello bro</h1><h2>Come On</h2><h3>Go sis</h3><ul><li>ME 1</li><li>ME 2</li></ul> <p>It is me bro , remember please</p>"

self.contentLabel.attributedText = str.htmlAttributedString()

0

सहायक एक्सटेंशन

इस सूत्र, एक फली, और iOS स्वादिष्ट कुकबुक p.80 में एरिका Sadun के ObjC उदाहरण से प्रेरित होकर, मैं पर एक विस्तार लिखा था Stringऔर पर NSAttributedStringआगे और पीछे एचटीएमएल सादे तार और NSAttributedStrings और उपाध्यक्ष के बीच विपरीत जाने के लिए - GitHub पर यहाँ है, जो मुझे मददगार मिल गया है।

हस्ताक्षर (फिर से, एक सार में पूर्ण कोड, ऊपर के लिंक) कर रहे हैं:

extension NSAttributedString {
    func encodedString(ext: DocEXT) -> String?
    static func fromEncodedString(_ eString: String, ext: DocEXT) -> NSAttributedString? 
    static func fromHTML(_ html: String) -> NSAttributedString? // same as above, where ext = .html
}

extension String {
    func attributedString(ext: DocEXT) -> NSAttributedString?
}

enum DocEXT: String { case rtfd, rtf, htm, html, txt }

0

फ़ॉन्ट के साथ

extension NSAttributedString
{
internal convenience init?(html: String, font: UIFont? = nil) {
    guard let data = html.data(using: String.Encoding.utf16, allowLossyConversion: false) else {
        return nil
    }
    assert(Thread.isMainThread)
    guard let attributedString = try?  NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) else {
        return nil
    }
    let mutable = NSMutableAttributedString(attributedString: attributedString)
    if let font = font {
        mutable.addAttribute(.font, value: font, range: NSRange(location: 0, length: mutable.length))
    }
    self.init(attributedString: mutable)
}
}

वैकल्पिक रूप से आप उन संस्करणों का उपयोग कर सकते हैं, जिन्हें यूआईबेल पर फॉन्ट किया गया था और एट्रिब्यूटिंग स्ट्रिंग सेट करने के बाद


0

रूपांतरण में निर्मित हमेशा UIColor.black के लिए पाठ रंग सेट करता है, भले ही आप .forgroundColor के साथ एक विशेषता शब्दकोश पास करते हैं जो कुछ और पर सेट हो। IOS 13 पर DARK मोड का समर्थन करने के लिए, NSAttributedString पर एक्सटेंशन के इस संस्करण को आज़माएं।

extension NSAttributedString {
    internal convenience init?(html: String)                    {
        guard 
            let data = html.data(using: String.Encoding.utf16, allowLossyConversion: false) else { return nil }

        let options : [DocumentReadingOptionKey : Any] = [
            .documentType: NSAttributedString.DocumentType.html,
            .characterEncoding: String.Encoding.utf8.rawValue
        ]

        guard
            let string = try? NSMutableAttributedString(data: data, options: options,
                                                 documentAttributes: nil) else { return nil }

        if #available(iOS 13, *) {
            let colour = [NSAttributedString.Key.foregroundColor: UIColor.label]
            string.addAttributes(colour, range: NSRange(location: 0, length: string.length))
        }

        self.init(attributedString: string)
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.