Преобразовать объект HTML в iOS Emoji? [Дубликат]

Я вытаскиваю JSON-файл с сайта, и одна из полученных строк:

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

Как я могу преобразовать такие вещи, как &#8216 в правильные символы?

Я продемонстрировал Xcode Playground:

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"])
84
задан akashivskyy 1 September 2014 в 14:52
поделиться

19 ответов

Нет простого способа сделать это, но вы можете использовать магию NSAttributedString, чтобы сделать этот процесс максимально безболезненным (следует предупредить, что этот метод также удалит все теги HTML):

let encodedString = "The Weeknd <em>&#8216;King Of The Fall&#8217;</em>"

// encodedString should = a[0]["title"] in your case

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

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

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

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

Не забудьте инициализировать NSAttributedString только из основного потока. Он использует некоторую магию WebKit под этим, поэтому это требование.


Вы можете создать собственное расширение String для увеличения повторного использования:

extension String {

    init?(htmlEncodedString: String) {

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

        let options: [String: Any] = [
            NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
            NSCharacterEncodingDocumentAttribute: 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)
124
ответ дан akashivskyy 18 August 2018 в 18:19
поделиться
  • 1
    +1 для ответа, -1 для предпочтения расширения по методу. Следующему разработчику будет непонятно, что stringByConvertingFromHTML является расширением, ясность - это самый важный атрибут, который может иметь программа. – zaph 1 September 2014 в 15:30
  • 2
    Какие? Расширения означают для расширения существующих типов для обеспечения новых функциональных возможностей. – akashivskyy 1 September 2014 в 22:24
  • 3
    Я понимаю, что вы пытаетесь сказать, но отрицание расширений - не выход. – akashivskyy 1 September 2014 в 22:29
  • 4
    @akashivskyy: Чтобы сделать эту работу правильно с символами, отличными от ASCII, вам нужно добавить NSCharacterEncodingDocumentAttribute, сравните stackoverflow.com/a/27898167/1187415 . – Martin R 25 April 2015 в 21:26
  • 5
    Этот метод чрезвычайно тяжелый и не рекомендуется в табличных обзорах или сетках – Guido Lodetti 2 September 2015 в 09:58

Swift 4


  • Расширение строки вычисляется var
  • Без дополнительной защиты / do / catch и т. д. ...
  • Возвращает оригинал строки при неудачном декодировании

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
    }
}
5
ответ дан AamirR 18 August 2018 в 18:19
поделиться
  • 1
    Вау ! работает прямо из коробки для Swift 4!. Использование // let encoded = & quot; The Weeknd & # 8216; King Of The Fall & amp; # 8217; & quot; let finalString = encoded.htmlDecoded – Naishta 11 August 2018 в 15:03

Это был бы мой подход. Вы можете добавить словарь сущностей из 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
ответ дан Bseaborn 18 August 2018 в 18:19
поделиться

Вычисленная версия var @yishus 'answer

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
        }
    }
}
27
ответ дан Community 18 August 2018 в 18:19
поделиться
  • 1
    Этот код является неполным и его следует избегать всеми способами. Ошибка не обрабатывается должным образом. Когда на самом деле произойдет сбой кода ошибки. Вы должны обновить свой код, чтобы хотя бы вернуть нуль при возникновении ошибки. Или вы можете просто начать с оригинальной строки. В конце вы должны обработать ошибку. Это не так. Вау! – oyalhi 25 April 2016 в 10:08
  • 2
    @oyalhi обновлено. – Zaid Pathan 31 May 2016 в 20:51
  • 3
    Прекрасно работает. Первоначальный ответ вызывал странный крах. Спасибо за обновление! – Geoherna 24 November 2016 в 09:10
  • 4
    Для французских персонажей я должен использовать utf16 – iLandes 29 August 2017 в 10:13

Посмотрите на HTMLString - библиотеку, написанную в Swift, которая позволяет вашей программе добавлять и удалять объекты HTML в Strings

. Для полноты я скопировал основные функции с сайта :

  • Добавляет сущности для кодировок ASCII и UTF-8 / UTF-16
  • Удаляет более 2100 именованных объектов (например, & amp;)
  • Поддерживает удаление десятичных и шестнадцатеричных сущностей
  • Предназначено для поддержки скользящих расширенных кластеров Grapheme (→ 100% emoji-proof)
  • Полностью модульное тестирование
  • Fast
  • Документировано
  • Совместимо с Objective-C
0
ответ дан Despotovic 18 August 2018 в 18:19
поделиться

версия Swift 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
ответ дан Fangming 18 August 2018 в 18:19
поделиться

Swift 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
}
1
ответ дан Haroldo Gondim 18 August 2018 в 18:19
поделиться

Elegant Swift 4 Solution

Если вы хотите, чтобы строка

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
ответ дан iLandes 18 August 2018 в 18:19
поделиться
Ответ

@ akashivskyy велик и демонстрирует, как использовать NSAttributedString для декодирования HTML-объектов. Одним из возможных недостатков (по его словам) является то, что удалена вся HTML-разметка 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.

Вот чистая реализация Swift. Он декодирует ссылки на объекты объектов, такие как &lt;, используя словарь, и все числовые символьные объекты, такие как &#64 или &#x20ac. (Обратите внимание, что я не перечислял все 252 элемента HTML явно.)

Swift 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 €.  @

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

Swift 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
    }
}
64
ответ дан Martin R 18 August 2018 в 18:19
поделиться
  • 1
    Это великолепно, спасибо Мартину! Вот расширение с полным списком сущностей HTML: gist.github.com/mwaterfall/25b4a6a06dc3309d9555 Я также немного адаптировал его для обеспечения смещений расстояния, сделанных заменами. Это позволяет правильно корректировать любые строковые атрибуты или объекты, на которые могут повлиять эти замены (например, индексы объектов Twitter). – Michael Waterfall 27 August 2015 в 17:11
  • 2
    @MichaelWaterfall и Martin это великолепно! работает как шарм! Я обновляю расширение для Swift 2 pastebin.com/juHRJ6au Спасибо! – Santiago 17 September 2015 в 22:29
  • 3
    Я применил этот ответ для совместимости с Swift 2 и сбрасывал его в CocoaPod под названием StringExtensionHTML для удобства использования. Обратите внимание, что версия Swift 2 от Santiago исправляет ошибки времени компиляции, но полная выгрузка strtooul(string, nil, base) приведет к тому, что код не будет работать с числовыми символьными сущностями и сбой, когда дело доходит до объекта, который он не распознает (вместо того, , – Adela Chang 15 April 2016 в 16:33
  • 4
    @AdelaChang: На самом деле, я уже перевел свой ответ на Swift 2 уже в сентябре 2015 года. Он все еще компилируется без предупреждений с Swift 2.2 / Xcode 7.3. Или вы имеете в виду версию Майкла? – Martin R 15 April 2016 в 18:02
  • 5
    Отличный ответ !!! Большое спасибо: D – Kwnstantinos Natsios 19 October 2016 в 11:33

Swift 4:

Общее решение, которое, наконец, работало для меня с html-кодом и символами новой строки и одиночными кавычками

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

Затем мне пришлось применить еще несколько фильтров, чтобы избавиться от single quotes (например: don't, hasn't, It's и т. д.), а также новые строковые символы, такие как \n

var yourNewString = String(yourStringEncoded.filter { !"\n\t\r".contains($0) })
yourNewString = yourNewString.replacingOccurrences(of: "\'", with: "", options: NSString.CompareOptions.literal, range: nil)
0
ответ дан Naishta 18 August 2018 в 18:19
поделиться

SWIFT 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)")

    }
}
0
ответ дан Omar Freewan 18 August 2018 в 18:19
поделиться
  • 1
    Пожалуйста, синтаксис rawValue NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.documentType.rawValue) и NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.characterEncoding.rawValue) ужасен. Замените его на .documentType и .characterEncoding – vadian 4 December 2017 в 13:11
  • 2
    Производительность этого решения ужасна. Возможно, это нормально для отдельных кешей, разбор файлов не рекомендуется. – Vincent 5 February 2018 в 11:19

Swift 4 Version

extension String {

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

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

    do {
        let attributedString = try NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil)
        self = attributedString.string
    } catch {
        print("Error: \(error)")
        self = htmlEncodedString
    }
  }
}
6
ответ дан pipizanzibar 18 August 2018 в 18:19
поделиться
  • 1
    Я получаю «Ошибка домена = NSCocoaErrorDomain Code = 259». Файл не может быть открыт, потому что он не в правильном формате. & Quot; & quot; когда я пытаюсь использовать это. Это уходит, если я запустил полный захват в основном потоке. Я нашел это от проверки документации NSAttributedString: «Импортёр HTML не следует вызывать из фонового потока (то есть, словарь параметров включает documentType со значением html). Он попытается синхронизировать с основным потоком, сбоем и тайм-аутом. & Quot; – MickeDG 17 October 2017 в 16:47
  • 2
    Пожалуйста, синтаксис rawValue NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.documentType.rawValue) и NSAttributedString.DocumentReadingOptionKey(rawValue: NSAttributedString.DocumentAttributeKey.characterEncoding.rawValue) ужасен. Замените его на .documentType и .characterEncoding – vadian 4 December 2017 в 13:09

Swift 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 = "string".replacingHTMLEntities!
0
ответ дан quemeful 18 August 2018 в 18:19
поделиться
  • 1
    Я уже слышу, как люди жалуются на то, что моя сила развернута факультативно. Если вы изучаете кодировку строки HTML, и вы не знаете, как бороться с опциями Swift, вы слишком далеко впереди себя. – quemeful 4 November 2017 в 17:03

Обновленный ответ, работающий над Swift 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)
}
1
ответ дан ravalboy 18 August 2018 в 18:19
поделиться

Swift4

Мне действительно нравится решение, использующее documentAttributes, однако оно может замедлить обработку файлов и / или использования в ячейках таблицы. Я не могу полагать, что Apple не дает достойного решения для этого.

В качестве обходного решения я нашел на GitHub это расширение строки, которое отлично и быстро работает для декодирования.

https://gist.github.com/mwaterfall/25b4a6a06dc3309d9555

Примечание: он не анализирует теги HTML.

0
ответ дан Vincent 18 August 2018 в 18:19
поделиться
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’
7
ответ дан wLc 18 August 2018 в 18:19
поделиться

NSData dataRes = (значение nsdata)

var resString = NSString (данные: dataRes, encoding: NSUTF8StringEncoding)

-1
ответ дан Yogesh shelke 18 August 2018 в 18:19
поделиться

Я искал чистую утилиту Swift 3.0 для перехода на / unescape из ссылок на символы HTML (то есть для приложений на стороне сервера Swift на MacOS и Linux), но не нашел комплексных решений, поэтому я написал свою собственную реализацию : https://github.com/IBM-Swift/swift-html-entities

Пакет, HTMLEntities, работает с символами HTML4 с именами символов, а также с шестнадцатеричным / dec числовые символьные ссылки, и он будет распознавать специальные числовые ссылки символов в спецификации W3 HTML5 (т. е. &#x80; не будет отображаться как знак Евро (unicode U+20AC) и NOT как символ Юникода для U+0080, а некоторые диапазоны

Пример использования:

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

И для примера OP:

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 теперь поддерживает ссылки на символы HTML5 с именами символов с версии 2.0.0. Также реализован синтаксический анализ, совместимый с параметрами.

4
ответ дан Youming Lin 18 August 2018 в 18:19
поделиться
  • 1
    Это самый общий ответ, который работает все время и не требует, чтобы его запускали в основном потоке. Это будет работать даже с самыми сложными строками unicode HTML (например, (&nbsp;͡&deg;&nbsp;͜ʖ&nbsp;͡&deg;&nbsp;)), тогда как ни один из других ответов не справится с этим. – Stéphane Copin 6 November 2017 в 15:13
27
ответ дан Community 7 September 2018 в 02:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: