मैं स्विफ्ट में HTML संस्थाओं को कैसे डिकोड कर सकता हूं?


121

मैं एक साइट से JSON फ़ाइल खींच रहा हूं और प्राप्त तार में से एक है:

The Weeknd ‘King Of The Fall’ [Video Premiere] | @TheWeeknd | #SoPhi

मैं चीजों &#8216को सही पात्रों में कैसे बदल सकता हूं ?

मैंने इसे प्रदर्शित करने के लिए एक Xcode खेल का मैदान बनाया है:

import UIKit

var error: NSError?
let blogUrl: NSURL = NSURL.URLWithString("http://sophisticatedignorance.net/api/get_recent_summary/")
let jsonData = NSData(contentsOfURL: blogUrl)

let dataDictionary = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) as NSDictionary

var a = dataDictionary["posts"] as NSArray

println(a[0]["title"])

जवाबों:


157

यह उत्तर अंतिम बार स्विफ्ट 5.2 और आईओएस 13.4 एसडीके के लिए संशोधित किया गया था।


ऐसा करने का कोई सरल तरीका नहीं है, लेकिन आप NSAttributedStringइस प्रक्रिया को यथासंभव दर्दनाक बनाने के लिए जादू का उपयोग कर सकते हैं (चेतावनी दें कि यह विधि सभी HTML टैग को भी छीन लेगी)।

केवल मुख्य धागे से आरंभ करनाNSAttributedString याद रखें । यह WebKit का उपयोग HTML को इस प्रकार पार्स करने के लिए करता है, इस प्रकार आवश्यकता है।

// This is a[0]["title"] in your case
let encodedString = "The Weeknd <em>&#8216;King Of The Fall&#8217;</em>"

guard let data = htmlEncodedString.data(using: .utf8) else {
    return
}

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

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

// The Weeknd ‘King Of The Fall’
let decodedString = attributedString.string
extension String {

    init?(htmlEncodedString: String) {

        guard let data = htmlEncodedString.data(using: .utf8) else {
            return nil
        }

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

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

        self.init(attributedString.string)

    }

}

let encodedString = "The Weeknd <em>&#8216;King Of The Fall&#8217;</em>"
let decodedString = String(htmlEncodedString: encodedString)

54
क्या? एक्सटेंशन कर रहे हैं मतलब मौजूदा प्रकार का विस्तार करने के लिए नई कार्यक्षमता प्रदान करने के लिए।
akashivskyy

4
मैं समझता हूं कि आप क्या कहना चाह रहे हैं, लेकिन एक्सटेंशन को नकारना जाने का तरीका नहीं है।
अकाशवस्की

1
@akashivskyy: गैर-एएससीआईआई पात्रों के साथ इस काम को सही तरीके से करने के लिए आपको एक NSCharacterEncodingDocumentAttribute को जोड़ना होगा, stackoverflow.com/a/27898167/1187415 से तुलना करनी होगी ।
मार्टिन आर

13
यह विधि अत्यंत भारी है और
तालिका-पत्रों

1
यह भी खूब रही! हालांकि यह मुख्य धागे को अवरुद्ध करता है, लेकिन क्या पृष्ठभूमि के धागे में इसे चलाने का कोई तरीका है?
MMV

78

@ akashivskyy का उत्तर बहुत अच्छा है और दर्शाता है कि NSAttributedStringHTML संस्थाओं को डिकोड कैसे किया जाए । एक संभावित नुकसान (जैसा कि उन्होंने कहा था) यह है कि सभी HTML मार्कअप को भी हटा दिया जाता है, इसलिए

<strong> 4 &lt; 5 &amp; 3 &gt; 2</strong>

हो जाता है

4 < 5 & 3 > 2

OS X पर, CFXMLCreateStringByUnescapingEntities()जो काम करता है:

let encoded = "<strong> 4 &lt; 5 &amp; 3 &gt; 2 .</strong> Price: 12 &#x20ac;.  &#64; "
let decoded = CFXMLCreateStringByUnescapingEntities(nil, encoded, nil) as String
println(decoded)
// <strong> 4 < 5 & 3 > 2 .</strong> Price: 12.  @ 

लेकिन यह iOS पर उपलब्ध नहीं है।

यहाँ एक शुद्ध स्विफ्ट कार्यान्वयन है। यह &lt;एक शब्दकोश का उपयोग करते हुए वर्ण संस्थाओं के संदर्भों को डिकोड करता है , और सभी संख्यात्मक वर्ण निकाय जैसे &#64या&#x20ac । (ध्यान दें कि मैंने सभी 252 HTML संस्थाओं को स्पष्ट रूप से सूचीबद्ध नहीं किया है।)

स्विफ्ट 4:

// Mapping from XML/HTML character entity reference to character
// From http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
private let characterEntities : [ Substring : Character ] = [
    // XML predefined entities:
    "&quot;"    : "\"",
    "&amp;"     : "&",
    "&apos;"    : "'",
    "&lt;"      : "<",
    "&gt;"      : ">",

    // HTML character entity references:
    "&nbsp;"    : "\u{00a0}",
    // ...
    "&diams;"   : "♦",
]

extension String {

    /// Returns a new string made by replacing in the `String`
    /// all HTML character entity references with the corresponding
    /// character.
    var stringByDecodingHTMLEntities : String {

        // ===== Utility functions =====

        // Convert the number in the string to the corresponding
        // Unicode character, e.g.
        //    decodeNumeric("64", 10)   --> "@"
        //    decodeNumeric("20ac", 16) --> "€"
        func decodeNumeric(_ string : Substring, base : Int) -> Character? {
            guard let code = UInt32(string, radix: base),
                let uniScalar = UnicodeScalar(code) else { return nil }
            return Character(uniScalar)
        }

        // Decode the HTML character entity to the corresponding
        // Unicode character, return `nil` for invalid input.
        //     decode("&#64;")    --> "@"
        //     decode("&#x20ac;") --> "€"
        //     decode("&lt;")     --> "<"
        //     decode("&foo;")    --> nil
        func decode(_ entity : Substring) -> Character? {

            if entity.hasPrefix("&#x") || entity.hasPrefix("&#X") {
                return decodeNumeric(entity.dropFirst(3).dropLast(), base: 16)
            } else if entity.hasPrefix("&#") {
                return decodeNumeric(entity.dropFirst(2).dropLast(), base: 10)
            } else {
                return characterEntities[entity]
            }
        }

        // ===== Method starts here =====

        var result = ""
        var position = startIndex

        // Find the next '&' and copy the characters preceding it to `result`:
        while let ampRange = self[position...].range(of: "&") {
            result.append(contentsOf: self[position ..< ampRange.lowerBound])
            position = ampRange.lowerBound

            // Find the next ';' and copy everything from '&' to ';' into `entity`
            guard let semiRange = self[position...].range(of: ";") else {
                // No matching ';'.
                break
            }
            let entity = self[position ..< semiRange.upperBound]
            position = semiRange.upperBound

            if let decoded = decode(entity) {
                // Replace by decoded character:
                result.append(decoded)
            } else {
                // Invalid entity, copy verbatim:
                result.append(contentsOf: entity)
            }
        }
        // Copy remaining characters to `result`:
        result.append(contentsOf: self[position...])
        return result
    }
}

उदाहरण:

let encoded = "<strong> 4 &lt; 5 &amp; 3 &gt; 2 .</strong> Price: 12 &#x20ac;.  &#64; "
let decoded = encoded.stringByDecodingHTMLEntities
print(decoded)
// <strong> 4 < 5 & 3 > 2 .</strong> Price: 12.  @

स्विफ्ट 3:

// Mapping from XML/HTML character entity reference to character
// From http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
private let characterEntities : [ String : Character ] = [
    // XML predefined entities:
    "&quot;"    : "\"",
    "&amp;"     : "&",
    "&apos;"    : "'",
    "&lt;"      : "<",
    "&gt;"      : ">",

    // HTML character entity references:
    "&nbsp;"    : "\u{00a0}",
    // ...
    "&diams;"   : "♦",
]

extension String {

    /// Returns a new string made by replacing in the `String`
    /// all HTML character entity references with the corresponding
    /// character.
    var stringByDecodingHTMLEntities : String {

        // ===== Utility functions =====

        // Convert the number in the string to the corresponding
        // Unicode character, e.g.
        //    decodeNumeric("64", 10)   --> "@"
        //    decodeNumeric("20ac", 16) --> "€"
        func decodeNumeric(_ string : String, base : Int) -> Character? {
            guard let code = UInt32(string, radix: base),
                let uniScalar = UnicodeScalar(code) else { return nil }
            return Character(uniScalar)
        }

        // Decode the HTML character entity to the corresponding
        // Unicode character, return `nil` for invalid input.
        //     decode("&#64;")    --> "@"
        //     decode("&#x20ac;") --> "€"
        //     decode("&lt;")     --> "<"
        //     decode("&foo;")    --> nil
        func decode(_ entity : String) -> Character? {

            if entity.hasPrefix("&#x") || entity.hasPrefix("&#X"){
                return decodeNumeric(entity.substring(with: entity.index(entity.startIndex, offsetBy: 3) ..< entity.index(entity.endIndex, offsetBy: -1)), base: 16)
            } else if entity.hasPrefix("&#") {
                return decodeNumeric(entity.substring(with: entity.index(entity.startIndex, offsetBy: 2) ..< entity.index(entity.endIndex, offsetBy: -1)), base: 10)
            } else {
                return characterEntities[entity]
            }
        }

        // ===== Method starts here =====

        var result = ""
        var position = startIndex

        // Find the next '&' and copy the characters preceding it to `result`:
        while let ampRange = self.range(of: "&", range: position ..< endIndex) {
            result.append(self[position ..< ampRange.lowerBound])
            position = ampRange.lowerBound

            // Find the next ';' and copy everything from '&' to ';' into `entity`
            if let semiRange = self.range(of: ";", range: position ..< endIndex) {
                let entity = self[position ..< semiRange.upperBound]
                position = semiRange.upperBound

                if let decoded = decode(entity) {
                    // Replace by decoded character:
                    result.append(decoded)
                } else {
                    // Invalid entity, copy verbatim:
                    result.append(entity)
                }
            } else {
                // No matching ';'.
                break
            }
        }
        // Copy remaining characters to `result`:
        result.append(self[position ..< endIndex])
        return result
    }
}

स्विफ्ट 2:

// Mapping from XML/HTML character entity reference to character
// From http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
private let characterEntities : [ String : Character ] = [
    // XML predefined entities:
    "&quot;"    : "\"",
    "&amp;"     : "&",
    "&apos;"    : "'",
    "&lt;"      : "<",
    "&gt;"      : ">",

    // HTML character entity references:
    "&nbsp;"    : "\u{00a0}",
    // ...
    "&diams;"   : "♦",
]

extension String {

    /// Returns a new string made by replacing in the `String`
    /// all HTML character entity references with the corresponding
    /// character.
    var stringByDecodingHTMLEntities : String {

        // ===== Utility functions =====

        // Convert the number in the string to the corresponding
        // Unicode character, e.g.
        //    decodeNumeric("64", 10)   --> "@"
        //    decodeNumeric("20ac", 16) --> "€"
        func decodeNumeric(string : String, base : Int32) -> Character? {
            let code = UInt32(strtoul(string, nil, base))
            return Character(UnicodeScalar(code))
        }

        // Decode the HTML character entity to the corresponding
        // Unicode character, return `nil` for invalid input.
        //     decode("&#64;")    --> "@"
        //     decode("&#x20ac;") --> "€"
        //     decode("&lt;")     --> "<"
        //     decode("&foo;")    --> nil
        func decode(entity : String) -> Character? {

            if entity.hasPrefix("&#x") || entity.hasPrefix("&#X"){
                return decodeNumeric(entity.substringFromIndex(entity.startIndex.advancedBy(3)), base: 16)
            } else if entity.hasPrefix("&#") {
                return decodeNumeric(entity.substringFromIndex(entity.startIndex.advancedBy(2)), base: 10)
            } else {
                return characterEntities[entity]
            }
        }

        // ===== Method starts here =====

        var result = ""
        var position = startIndex

        // Find the next '&' and copy the characters preceding it to `result`:
        while let ampRange = self.rangeOfString("&", range: position ..< endIndex) {
            result.appendContentsOf(self[position ..< ampRange.startIndex])
            position = ampRange.startIndex

            // Find the next ';' and copy everything from '&' to ';' into `entity`
            if let semiRange = self.rangeOfString(";", range: position ..< endIndex) {
                let entity = self[position ..< semiRange.endIndex]
                position = semiRange.endIndex

                if let decoded = decode(entity) {
                    // Replace by decoded character:
                    result.append(decoded)
                } else {
                    // Invalid entity, copy verbatim:
                    result.appendContentsOf(entity)
                }
            } else {
                // No matching ';'.
                break
            }
        }
        // Copy remaining characters to `result`:
        result.appendContentsOf(self[position ..< endIndex])
        return result
    }
}

10
यह शानदार है, धन्यवाद मार्टिन! यहाँ HTML संस्थाओं की पूरी सूची के साथ विस्तार किया गया है: gist.github.com/mwaterfall/25b4a6a06dc3309d9555 मैंने इसे प्रतिस्थापन द्वारा दूरी दूरी प्रदान करने के लिए भी थोड़ा अनुकूलित किया है। यह किसी भी स्ट्रिंग विशेषताओं या संस्थाओं के सही समायोजन की अनुमति देता है जो इन प्रतिस्थापनों से प्रभावित हो सकते हैं (उदाहरण के लिए ट्विटर इकाई सूचकांक)।
माइकल वाटरफॉल

3
@MichaelWaterfall और मार्टिन यह शानदार है! एक जादू की तरह काम करता है! मैं स्विफ्ट 2 pastebin.com/juHRJ6au के लिए एक्सटेंशन को अपडेट करता हूं धन्यवाद!
सांतियागो

1
मैंने इस उत्तर को स्विफ्ट 2 के साथ संगत किया और उपयोग में आसानी के लिए इसे StringExtensionHTML नामक कोकोआपोड में डंप कर दिया । ध्यान दें कि सैंटियागो का स्विफ्ट 2 संस्करण संकलन समय त्रुटियों को ठीक करता है, लेकिन strtooul(string, nil, base)पूरी तरह से कोड को लेने से संख्यात्मक चरित्र संस्थाओं के साथ काम नहीं करेगा और जब यह एक इकाई की बात आती है तो दुर्घटना नहीं होती है जो इसे पहचान नहीं करता है (बजाय इनायत के असफल)।
अडेला चांग

1
@ AdelaChang: वास्तव में मैंने अपना उत्तर सितंबर 2015 में पहले ही स्विफ्ट 2 में बदल दिया था। यह अभी भी स्विफ्ट 2.2 / एक्सकोड 7.3 के साथ चेतावनी के बिना संकलित करता है। या आप माइकल के संस्करण का उल्लेख कर रहे हैं?
मार्टिन आर।

1
धन्यवाद, इस उत्तर के साथ मैंने अपने मुद्दों को हल किया: मुझे NSAttributedString का उपयोग करके गंभीर प्रदर्शन समस्याएं थीं।
एंड्रिया मुगनैनी

27

@ Akashivskyy के विस्तार का 3 संस्करण स्विफ्ट ,

extension String {
    init(htmlEncodedString: String) {
        self.init()
        guard let encodedData = htmlEncodedString.data(using: .utf8) else {
            self = htmlEncodedString
            return
        }

        let attributedOptions: [String : Any] = [
            NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
            NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue
        ]

        do {
            let attributedString = try NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil)
            self = attributedString.string
        } catch {
            print("Error: \(error)")
            self = htmlEncodedString
        }
    }
}

बहुत अच्छा काम करता है। मूल उत्तर अजीब दुर्घटना का कारण बन रहा था। अपडेट के लिए धन्यवाद!
जियोहर्ना

फ्रेंच अक्षरों के लिए मुझे utf16
Sébastien REMY

23

स्विफ्ट 4


  • स्ट्रिंग विस्तार कम्प्यूटेड चर
  • अतिरिक्त गार्ड के बिना, कैच, आदि करें ...
  • डिकोडिंग विफल होने पर मूल तार लौटाता है

extension String {
    var htmlDecoded: String {
        let decoded = try? NSAttributedString(data: Data(utf8), options: [
            .documentType: NSAttributedString.DocumentType.html,
            .characterEncoding: String.Encoding.utf8.rawValue
        ], documentAttributes: nil).string

        return decoded ?? self
    }
}

1
वाह ! स्विफ्ट 4 के लिए बॉक्स के ठीक बाहर काम करता है! उपयोग // आइए एन्कोडेड = "द वीकेंड & # 8216; द फॉल के राजा & # 8217;" आज्ञा देना अंतिम सांकेतिक = एन्कोडेड.htmlDecoded
Naishta

2
मुझे इस उत्तर की सादगी बहुत पसंद है। हालांकि, यह पृष्ठभूमि में चलने पर क्रैश का कारण बनेगा क्योंकि यह मुख्य धागे पर चलने की कोशिश करता है।
जेरेमी हिक्स

14

@ Akashivskyy के एक्सटेंशन का 2 संस्करण स्विफ्ट ,

 extension String {
     init(htmlEncodedString: String) {
         if let encodedData = htmlEncodedString.dataUsingEncoding(NSUTF8StringEncoding){
             let attributedOptions : [String: AnyObject] = [
            NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
            NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding
        ]

             do{
                 if let attributedString:NSAttributedString = try NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil){
                     self.init(attributedString.string)
                 }else{
                     print("error")
                     self.init(htmlEncodedString)     //Returning actual string if there is an error
                 }
             }catch{
                 print("error: \(error)")
                 self.init(htmlEncodedString)     //Returning actual string if there is an error
             }

         }else{
             self.init(htmlEncodedString)     //Returning actual string if there is an error
         }
     }
 }

यह कोड अधूरा है और इसे हर तरह से टाला जाना चाहिए। त्रुटि को ठीक से नियंत्रित नहीं किया जा रहा है। जब वास्तव में कोई त्रुटि कोड क्रैश होता है। त्रुटि होने पर आपको कम से कम रिटर्न में अपना कोड अपडेट करना चाहिए। या आप मूल स्ट्रिंग के साथ सिर्फ init कर सकते हैं। अंत में आपको त्रुटि को संभालना चाहिए। जो मामला न हो। वाह!
इलोहि

9

स्विफ्ट 4 संस्करण

extension String {

    init(htmlEncodedString: String) {
        self.init()
        guard let encodedData = htmlEncodedString.data(using: .utf8) else {
            self = htmlEncodedString
            return
        }

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

        do {
            let attributedString = try NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil)
            self = attributedString.string
        } 
        catch {
            print("Error: \(error)")
            self = htmlEncodedString
        }
    }
}

मुझे "त्रुटि डोमेन = NSCocoaErrorDomain कोड = 259" मिलता है, क्योंकि यह सही प्रारूप में नहीं है, इसलिए फ़ाइल नहीं खोली जा सकती। "" जब मैं इसका उपयोग करने की कोशिश करता हूं। यह पूरा हो जाता है अगर मैं मुख्य धागे पर पूरा करते हैं। मैंने NSAttributedString प्रलेखन की जाँच करने से यह पाया: "HTML आयातक को पृष्ठभूमि थ्रेड से नहीं बुलाया जाना चाहिए (अर्थात, विकल्प शब्दकोश में HTML के मान के साथ डॉक्यूमेंट टाइप शामिल है।) यह मुख्य थ्रेड के साथ सिंक्रनाइज़ करने का प्रयास करेगा, विफल और। समय समाप्त।"
मिकडेग

8
कृपया, rawValueवाक्यविन्यास NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.documentType.rawValue)और NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.characterEncoding.rawValue)भयानक है। इसे .documentType.characterEncoding
बदलिए

@MickeDG - क्या आप बता सकते हैं कि इस त्रुटि को हल करने के लिए आपने वास्तव में क्या किया? मैं इसे छिटपुट रूप से प्राप्त कर रहा हूं।
रॉस बारबिश

@RossBarbish - क्षमा करें रॉस, यह बहुत पहले था, विवरण याद नहीं कर सकते। क्या आपने कोशिश की है जो मैं ऊपर टिप्पणी में सुझाता हूं, यानी मुख्य धागे पर पूरा पकड़ने के लिए?
मकीडेग

7
extension String{
    func decodeEnt() -> String{
        let encodedData = self.dataUsingEncoding(NSUTF8StringEncoding)!
        let attributedOptions : [String: AnyObject] = [
            NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
            NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding
        ]
        let attributedString = NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil, error: nil)!

        return attributedString.string
    }
}

let encodedString = "The Weeknd &#8216;King Of The Fall&#8217;"

let foo = encodedString.decodeEnt() /* The Weeknd ‘King Of The Fall’ */

पुन "Weeknd" : नहीं "वीकेंड" ?
पीटर मोर्टेंसन

वाक्य रचना हाइलाइटिंग अजीब लगती है, विशेष रूप से अंतिम पंक्ति का टिप्पणी हिस्सा। क्या आप इसे ठीक कर सकते हैं?
पीटर मोर्टेंसन

"द वीकेंड" एक गायक है, और हाँ, यही उसका नाम है।
wlc

5

मैं HTML चरित्र संदर्भों से बचने के लिए / unescape के लिए शुद्ध स्विफ्ट 3.0 उपयोगिता की तलाश कर रहा था (यानी macOS और लिनक्स दोनों पर सर्वर-साइड स्विफ्ट ऐप्स के लिए) लेकिन कोई व्यापक समाधान नहीं मिला, इसलिए मैंने अपना स्वयं का कार्यान्वयन लिखा: https: //github.com/IBM-Swift/swift-html-entities

पैकेज, HTMLEntitiesएचटीएमएल 4 नामित चरित्र संदर्भों के साथ-साथ हेक्स / डिक न्यूमेरिक कैरेक्टर संदर्भों के साथ काम करता है, और यह डब्ल्यू 3 एचटीएमएल 5 युक्ति के अनुसार विशेष संख्यात्मक चरित्र संदर्भों को पहचानेगा (अर्थात &#x80;यूरो चिह्न (यूनिकोड U+20AC) और यूनिकोड के रूप में नहीं होना चाहिए ) के लिए चरित्र U+0080, और संख्यात्मक चरित्र संदर्भों की कुछ श्रेणियों को प्रतिस्थापन चरित्र के साथ प्रतिस्थापित किया जाना चाहिएU+FFFD जब उन्हें जाए)।

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

import HTMLEntities

// encode example
let html = "<script>alert(\"abc\")</script>"

print(html.htmlEscape())
// Prints ”&lt;script&gt;alert(&quot;abc&quot;)&lt;/script&gt;"

// decode example
let htmlencoded = "&lt;script&gt;alert(&quot;abc&quot;)&lt;/script&gt;"

print(htmlencoded.htmlUnescape())
// Prints<script>alert(\"abc\")</script>"

और ओपी के उदाहरण के लिए:

print("The Weeknd &#8216;King Of The Fall&#8217; [Video Premiere] | @TheWeeknd | #SoPhi ".htmlUnescape())
// prints "The Weeknd ‘King Of The Fall’ [Video Premiere] | @TheWeeknd | #SoPhi "

संपादित करें: HTMLEntitiesअब संस्करण 2.0.0 के रूप में एचटीएमएल 5 नामित चरित्र संदर्भों का समर्थन करता है। विशिष्ट-संगत पार्सिंग भी लागू किया गया है।


1
यह सबसे सामान्य उत्तर है जो हर समय काम करता है, और मुख्य धागे पर चलने की आवश्यकता नहीं है। यह सबसे जटिल HTML के साथ भी काम करेगा, जो यूनिकोड स्ट्रिंग्स (जैसे जैसे (&nbsp;͡&deg;&nbsp;͜ʖ&nbsp;͡&deg;&nbsp;)) से बच गया , जबकि अन्य कोई भी उत्तर ऐसा नहीं है।
स्टीफन कोपिन

5

स्विफ्ट 4:

कुल समाधान है कि अंत में मेरे लिए HTML कोड और newline वर्ण और एकल उद्धरण के साथ काम किया

extension String {
    var htmlDecoded: String {
        let decoded = try? NSAttributedString(data: Data(utf8), options: [
            .documentType: NSAttributedString.DocumentType.html,
            .characterEncoding: String.Encoding.utf8.rawValue
            ], documentAttributes: nil).string

        return decoded ?? self
    }
}

उपयोग:

let yourStringEncoded = yourStringWithHtmlcode.htmlDecoded

मुझे तब एकल उद्धरण से छुटकारा पाने के लिए कुछ और फिल्टर लगाने पड़े (उदाहरण के लिए, नहीं ,) नहीं , यह , आदि), और नए अक्षर हैं \n:

var yourNewString = String(yourStringEncoded.filter { !"\n\t\r".contains($0) })
yourNewString = yourNewString.replacingOccurrences(of: "\'", with: "", options: NSString.CompareOptions.literal, range: nil)

यह अनिवार्य रूप से इस अन्य उत्तर की एक प्रति है । आपने जो कुछ किया है वह कुछ उपयोग है जो स्पष्ट रूप से पर्याप्त है।
राम

कुछ लोगों ने इस उत्तर को उकेरा है और इसे वास्तव में उपयोगी पाया है, जो आपको बताता है?
निशा

@ निश्चय यह बताता है कि सभी की अलग-अलग राय है और यह ठीक है
जोश वोल्फ

3

यह मेरा दृष्टिकोण होगा। आप https://gist.github.com/mwaterfall/25b4a6a06dc3309d9555 माइकल वाटरफॉल में उल्लेख कर सकते हैं।

extension String {
    func htmlDecoded()->String {

        guard (self != "") else { return self }

        var newStr = self

        let entities = [
            "&quot;"    : "\"",
            "&amp;"     : "&",
            "&apos;"    : "'",
            "&lt;"      : "<",
            "&gt;"      : ">",
        ]

        for (name,value) in entities {
            newStr = newStr.stringByReplacingOccurrencesOfString(name, withString: value)
        }
        return newStr
    }
}

उपयोग किए गए उदाहरण:

let encoded = "this is so &quot;good&quot;"
let decoded = encoded.htmlDecoded() // "this is so "good""

या

let encoded = "this is so &quot;good&quot;".htmlDecoded() // "this is so "good""

1
मैं काफी यह पसंद नहीं है, लेकिन मैं कुछ भी नहीं मिला बेहतर अभी तक तो यह स्विफ्ट 2.0 के लिए माइकल झरना समाधान के एक अद्यतन संस्करण है gist.github.com/jrmgx/3f9f1d330b295cf6b1c6
jrmgx

3

सुरुचिपूर्ण स्विफ्ट 4 समाधान

यदि आप एक तार चाहते हैं,

myString = String(htmlString: encodedString)

इस विस्तार को अपनी परियोजना में जोड़ें:

extension String {

    init(htmlString: String) {
        self.init()
        guard let encodedData = htmlString.data(using: .utf8) else {
            self = htmlString
            return
        }

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

        do {
            let attributedString = try NSAttributedString(data: encodedData,
                                                          options: attributedOptions,
                                                          documentAttributes: nil)
            self = attributedString.string
        } catch {
            print("Error: \(error.localizedDescription)")
            self = htmlString
        }
    }
}

यदि आप एक NSAttributedString को बोल्ड, इटैलिक, लिंक आदि के साथ चाहते हैं।

textField.attributedText = try? NSAttributedString(htmlString: encodedString)

इस विस्तार को अपनी परियोजना में जोड़ें:

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

}

2

@Yishus के उत्तर का कम्प्यूटेड संस्करण संस्करण

public extension String {
    /// Decodes string with HTML encoding.
    var htmlDecoded: String {
        guard let encodedData = self.data(using: .utf8) else { return self }

        let attributedOptions: [String : Any] = [
            NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
            NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue]

        do {
            let attributedString = try NSAttributedString(data: encodedData,
                                                          options: attributedOptions,
                                                          documentAttributes: nil)
            return attributedString.string
        } catch {
            print("Error: \(error)")
            return self
        }
    }
}

1

स्विफ्ट 4

func decodeHTML(string: String) -> String? {

    var decodedString: String?

    if let encodedData = string.data(using: .utf8) {
        let attributedOptions: [NSAttributedString.DocumentReadingOptionKey : Any] = [
            .documentType: NSAttributedString.DocumentType.html,
            .characterEncoding: String.Encoding.utf8.rawValue
        ]

        do {
            decodedString = try NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil).string
        } catch {
            print("\(error.localizedDescription)")
        }
    }

    return decodedString
}

एक स्पष्टीकरण क्रम में होगा। उदाहरण के लिए, यह पिछले स्विफ्ट 4 उत्तरों से कैसे अलग है?
पीटर मोर्टेंसन

1

स्विफ्ट 4.1 +

var htmlDecoded: String {


    let attributedOptions: [NSAttributedString.DocumentReadingOptionKey : Any] = [

        NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html,
        NSAttributedString.DocumentReadingOptionKey.characterEncoding : String.Encoding.utf8.rawValue
    ]


    let decoded = try? NSAttributedString(data: Data(utf8), options: attributedOptions
        , documentAttributes: nil).string

    return decoded ?? self
} 

एक स्पष्टीकरण क्रम में होगा। उदाहरण के लिए, यह पिछले उत्तरों से कैसे भिन्न है? स्विफ्ट 4.1 सुविधाओं का क्या उपयोग किया जाता है? क्या यह केवल स्विफ्ट 4.1 में काम करता है और पिछले संस्करणों में नहीं? या यह स्विफ्ट 4.1 से पहले काम करेगा, स्विफ्ट 4.0 में कहेंगे?
पीटर मोर्टेंसन

1

स्विफ्ट 4

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

सरल उपयोग

let clean = "Weeknd &#8216;King Of The Fall&#8217".replacingHTMLEntities ?? "default value"

मैं पहले से ही अपने बल के बारे में शिकायत कर रहे लोगों को वैकल्पिक रूप से नहीं सुन सकता। यदि आप HTML स्ट्रिंग एन्कोडिंग पर शोध कर रहे हैं और आप नहीं जानते कि स्विफ्ट ऑप्शंस से कैसे निपटें, तो आप खुद से बहुत आगे हैं।
quemeful

हाँ, वहाँ 22:37 पर ( 1 नवंबर को संपादित किया गया था और "सरल उपयोग" को समझने के लिए बहुत कठिन बना दिया)
quemeful

1

स्विफ्ट 4

मैं वास्तव में documentAttributes का उपयोग कर समाधान पसंद करता हूं। हालाँकि, यह पार्सिंग फ़ाइलों और / या टेबल व्यू कोशिकाओं में उपयोग के लिए बहुत धीमा हो सकता है। मुझे विश्वास नहीं हो रहा है कि Apple इसके लिए एक अच्छा समाधान प्रदान नहीं करता है।

वर्कअराउंड के रूप में, मुझे GitHub पर यह स्ट्रिंग एक्सटेंशन मिला जो पूरी तरह से काम करता है और डिकोडिंग के लिए तेज़ है।

तो उन स्थितियों के लिए जिनमें दिए गए उत्तर को धीमा करना है , इस लिंक में समाधान का सुझाव देखें: https://gist.github.com/mwaterfall/25b4a6a06dc3309d9555

नोट: यह HTML टैग को पार्स नहीं करता है।


1

स्विफ्ट 3 पर काम करने वाले अपडेटेड उत्तर

extension String {
    init?(htmlEncodedString: String) {
        let encodedData = htmlEncodedString.data(using: String.Encoding.utf8)!
        let attributedOptions = [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]

        guard let attributedString = try? NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil) else {
            return nil
        }
        self.init(attributedString.string)
   }

0

उद्देश्य सी

+(NSString *) decodeHTMLEnocdedString:(NSString *)htmlEncodedString {
    if (!htmlEncodedString) {
        return nil;
    }

    NSData *data = [htmlEncodedString dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *attributes = @{NSDocumentTypeDocumentAttribute:     NSHTMLTextDocumentType,
                             NSCharacterEncodingDocumentAttribute:     @(NSUTF8StringEncoding)};
    NSAttributedString *attributedString = [[NSAttributedString alloc]     initWithData:data options:attributes documentAttributes:nil error:nil];
    return [attributedString string];
}

0

वास्तविक फ़ॉन्ट आकार रूपांतरण के साथ 3.0 संस्करण स्विफ्ट

आम तौर पर, यदि आप सीधे HTML सामग्री को एक जिम्मेदार स्ट्रिंग में परिवर्तित करते हैं, तो फ़ॉन्ट आकार बढ़ जाता है। आप अंतर देखने के लिए HTML स्ट्रिंग को एक जिम्मेदार स्ट्रिंग में बदलने और फिर से वापस करने का प्रयास कर सकते हैं।

इसके बजाय, यहां वास्तविक आकार रूपांतरण है जो यह सुनिश्चित करता है कि सभी फ़ॉन्ट पर 0.75 अनुपात लागू करने से फ़ॉन्ट आकार नहीं बदलता है:

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

0

स्विफ्ट 4

extension String {

    mutating func toHtmlEncodedString() {
        guard let encodedData = self.data(using: .utf8) else {
            return
        }

        let attributedOptions: [NSAttributedString.DocumentReadingOptionKey : Any] = [
            NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.documentType.rawValue): NSAttributedString.DocumentType.html,
            NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.characterEncoding.rawValue): String.Encoding.utf8.rawValue
        ]

        do {
            let attributedString = try NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil)
            self = attributedString.string
        }
        catch {
            print("Error: \(error)")
        }
    }

कृपया, rawValueवाक्यविन्यास NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.documentType.rawValue)और NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.characterEncoding.rawValue)भयानक है। इसे बदलें .documentTypeऔर.characterEncoding
vadian

इस समाधान का प्रदर्शन भयानक है। यह अलग caes के लिए शायद ठीक है, पार्सिंग फ़ाइलों की सलाह नहीं दी जाती है।
विंसेंट

0

HTMLString पर एक नज़र डालें - स्विफ्ट में लिखी गई एक लाइब्रेरी जो आपके प्रोग्राम को स्ट्रिंग्स में HTML संस्थाओं को जोड़ने और हटाने की अनुमति देती है

पूर्णता के लिए, मैंने साइट से मुख्य विशेषताओं की प्रतिलिपि बनाई:

  • ASCII और UTF-8 / UTF-16 एन्कोडिंग के लिए संस्थाओं को जोड़ता है
  • 2100 से अधिक नामित संस्थाएं (जैसे और) निकालता है
  • दशमलव और हेक्साडेसिमल संस्थाओं को हटाने का समर्थन करता है
  • स्विफ्ट एक्सटेंडेड ग्रेफेम क्लस्टर्स (→ 100% इमोजी-प्रूफ) का समर्थन करने के लिए डिज़ाइन किया गया
  • पूरी तरह से इकाई परीक्षण किया गया
  • तेज
  • प्रलेखित
  • उद्देश्य-सी के साथ संगत

0

स्विफ्ट 5.1 संस्करण

import UIKit

extension String {

    init(htmlEncodedString: String) {
        self.init()
        guard let encodedData = htmlEncodedString.data(using: .utf8) else {
            self = htmlEncodedString
            return
        }

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

        do {
            let attributedString = try NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil)
            self = attributedString.string
        } 
        catch {
            print("Error: \(error)")
            self = htmlEncodedString
        }
    }
}

इसके अलावा, यदि आप तिथि, चित्र, मेटाडेटा, शीर्षक और विवरण निकालना चाहते हैं, तो आप मेरी फली नाम का उपयोग कर सकते हैं:

] [1]

पठनीयता किट


ऐसा क्या है जो इसे कुछ पूर्व संस्करणों में काम नहीं करेगा, स्विफ्ट 5.0, स्विफ्ट 4.1, स्विफ्ट 4.0, आदि।
पीटर मोर्टेंसन

मुझे एक त्रुटि मिली जब संग्रह
दृश्य

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