programing

iOS에서 HTML을 NSA 속성 문자열로 변환

megabox 2023. 4. 29. 09:09
반응형

iOS에서 HTML을 NSA 속성 문자열로 변환

의 인스턴스를 사용하고 있습니다.UIWebView을 지정하기 하지만, 부텍스를로정색위해칠기하일게, 은결를과대 에 표시하는 로 제공합니다.UIWebView을 다을사용표다니합시여음하를 사용하여 표시하고 싶습니다.Core TextNSAttributedString.

나는 창조하고 그릴 수 있습니다.NSAttributedStringHTML을 어떻게 변환하고 속성 문자열에 매핑할 수 있는지 잘 모르겠습니다.

X Mac OS X 아래에 있습니다.NSAttributedString을 가지고 있습니다.initWithHTML:할 수 없습니다. method는 Mac에서 사용할 수 없습니다. method는 iOS에서 사용할 수 있습니다.

저도 이것과 비슷한 질문이 있다는 것을 알고 있지만 답이 없었습니다. 저는 누군가가 이것을 할 수 있는 방법을 만들었는지, 만약 그렇다면 공유할 수 있는지 다시 한번 시도해보고 싶다고 생각했습니다.

iOS 7에서 UIKit은 초기화할 수 있는 방법을 추가했습니다.NSAttributedStringHTML 사용(예:

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

Swift에서:

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)

Github의 Oliver Drobnik이 NSA에서 제공하는 문자열에 대한 오픈 소스 추가 작업이 진행 중입니다.HTML 구문 분석에 NS 스캐너를 사용합니다.

HTML에서 NSA 속성 문자열을 생성하려면 메인 스레드에서 수행해야 합니다!

업데이트: NSA 속성 String HTML 렌더링은 후드 아래의 WebKit에 의존하며 메인 스레드에서 실행되어야 하며 그렇지 않으면 SIGTRAP로 앱이 충돌하는 경우가 있습니다.

새 유물 충돌 로그:

여기에 이미지 설명 입력

다음은 스레드 세이프 Swift 2 String 확장 버전 업데이트입니다.

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
}

출력:

여기에 이미지 설명 입력

NSA 속성 문자열의 빠른 초기화자 확장

제 성향은 이것을 확장으로 추가하는 것이었습니다.NSAttributedStringString정적 확장과 이니셜라이저로 사용해 보았습니다.저는 아래에 포함된 이니셜라이저를 선호합니다.

스위프트 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)

은 이은입니다.String 을 HTML로 입니다.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()

위에서 유니코드를 올바르게 렌더링한다는 것을 보여주기 위해 일부러 유니코드 \u22022를 추가했습니다.

기본 : 기본 인코딩으로 되는 인코딩입니다.NSAttributedString은 도는용입니다.NSUTF16StringEncoding(UTF8 사용!).

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

Andrew의 솔루션을 수정하고 코드를 Swift 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 }

스위프트 4


  • NSA 속성 문자열 편의성 초기화자
  • 추가 경비 없이
  • 오류 발생

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

NSHTML 텍스트 문서 사용유형은 느리고 스타일을 제어하기 어렵습니다.저는 당신이 아트리부티카라고 불리는 제 도서관에 가보는 것을 제안합니다.그것은 매우 빠른 HTML 파서를 가지고 있습니다.또한 태그 이름을 지정하고 원하는 스타일을 정의할 수 있습니다.

예:

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

label.attributedText = str

https://github.com/psharanda/Atributika 에서 찾을 수 있습니다.

현재 유일한 해결책은 HTML을 구문 분석하고 지정된 point/font/etc 속성을 가진 노드를 구축한 다음 이들 노드를 NSA 속성 문자열로 결합하는 것입니다.많은 작업이 필요하지만 올바르게 수행되면 미래에 재사용할 수 있습니다.

스위프트 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()

위의 해결책이 맞습니다.

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

그러나 ios 8.1, 2 또는 3에서 실행하면 앱이 충돌합니다.

충돌을 방지하기 위해 대기열에서 실행할 수 있습니다.그래서 항상 메인 스레드에 있습니다.

.forgroundColor가 설정된 속성 사전을 다른 항목으로 전달하는 경우에도 내장 변환은 항상 텍스트 색상을 UIColor.black으로 설정합니다.iOS 13에서 DARK 모드를 지원하려면 NSA 속성 문자열에서 이 확장 버전을 사용해 보십시오.

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

여기 있습니다.Swift 5Mobile Dan의 답변 버전:

public extension NSAttributedString {
    convenience init?(_ html: String) {
        guard let data = html.data(using: .unicode) else {
                return nil
        }

        try? self.init(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
    }
}

유용한 확장 기능

iOS Gourmet Cookbook p.80에 있는 이 실과 포드, 그리고 Erica Sadun의 ObjC 예시에서 영감을 받아, 저는 확장을 썼습니다.String등등NSAttributedStringHTML 플레인 스트링과 NSA 속성 스트링 사이를 왔다 갔다 하거나 그 반대로 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 }

폰트 계열, 동적 폰트에 경의를 표합니다. 제가 이 혐오감을 만들어냈습니다.

extension NSAttributedString
{
    convenience fileprivate init?(html: String, font: UIFont? = Font.dynamic(style: .subheadline))
    {
        guard let data = html.data(using: String.Encoding.utf8, allowLossyConversion: true) else {
        var totalString = html
        /*
         https://stackoverflow.com/questions/32660748/how-to-use-apples-new-san-francisco-font-on-a-webpage
            .AppleSystemUIFont I get in font.familyName does not work
         while -apple-system does:
         */
        var ffamily = "-apple-system"
        if let font = font {
            let lLDBsucks = font.familyName
            if !lLDBsucks.hasPrefix(".appleSystem") {
                ffamily = font.familyName
            }
            totalString = "<style>\nhtml * {font-family: \(ffamily) !important;}\n            </style>\n" + html
        }
        guard let data = totalString.data(using: String.Encoding.utf8, allowLossyConversion: true) else {
            return nil
        }
        assert(Thread.isMainThread)
        guard let attributedText = try?  NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) else {
            return nil
        }
        let mutable = NSMutableAttributedString(attributedString: attributedText)
        if let font = font {
        do {
            var found = false
            mutable.beginEditing()
            mutable.enumerateAttribute(NSAttributedString.Key.font, in: NSMakeRange(0, attributedText.length), options: NSAttributedString.EnumerationOptions(rawValue: 0)) { (value, range, stop) in
                    if let oldFont = value as? UIFont {
                        let newsize = oldFont.pointSize * 15 * Font.scaleHeruistic / 12
                        let newFont = oldFont.withSize(newsize)
                        mutable.addAttribute(NSAttributedString.Key.font, value: newFont, range: range)
                        found = true
                    }
                }
                if !found {
                    // No font was found - do something else?
                }

            mutable.endEditing()
            
//            mutable.addAttribute(.font, value: font, range: NSRange(location: 0, length: mutable.length))
        }
        self.init(attributedString: mutable)
    }

}

또는 이것이 파생된 버전을 사용하고 attributedString을 설정한 후 UILabel에 글꼴을 설정할 수 있습니다.

이것은 속성 문자열에 캡슐화된 크기와 대담성을 포함합니다.

여기까지 모든 답을 읽어주셔서 감사합니다.당신은 매우 인내심이 많은 남자 여자나 아이입니다.

html을 Attributed NSAttributedString으로 변환하여 동적 크기 + 텍스트에 대한 접근성을 조정하는 함수입니다.

static func convertHtml(string: String?) -> NSAttributedString? {
    
    guard let string = string else {return nil}
    
    guard let data = string.data(using: .utf8) else {
        return nil
    }
    
    do {
        let attrStr = try NSAttributedString(data: data,
                                      options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue],
                                      documentAttributes: nil)
        let range = NSRange(location: 0, length: attrStr.length)
        let str = NSMutableAttributedString(attributedString: attrStr)
        
        str.enumerateAttribute(NSAttributedString.Key.font, in: NSMakeRange(0, str.length), options: .longestEffectiveRangeNotRequired) {
            (value, range, stop) in
            if let font = value as? UIFont {
                
                let userFont =  UIFontDescriptor.preferredFontDescriptor(withTextStyle: .title2)
                let pointSize = userFont.withSize(font.pointSize)
                let customFont = UIFont.systemFont(ofSize: pointSize.pointSize)
                let dynamicText = UIFontMetrics.default.scaledFont(for: customFont)
                str.addAttribute(NSAttributedString.Key.font,
                                         value: dynamicText,
                                         range: range)
            }
        }

        str.addAttribute(NSAttributedString.Key.underlineStyle, value: 0, range: range)
        
        return NSAttributedString(attributedString: str.attributedSubstring(from: range))
    } catch {}
    return nil
    
}

사용 방법:

let htmToStringText = convertHtml(string: html)
            
  self.bodyTextView.isEditable = false
  self.bodyTextView.isAccessibilityElement = true
  self.bodyTextView.adjustsFontForContentSizeCategory = true
  self.bodyTextView.attributedText = htmToStringText
  self.bodyTextView.accessibilityAttributedLabel = htmToStringText

이 확장자를 추가한 다음 텍스트를 사용합니다. 이 코드를 사용한 후 텍스트의 사용자 정의 크기를 사용할 수 있습니다.

extension Text {
    init(html htmlString: String,
         raw: Bool = false,
         size: CGFloat? = nil,
         fontFamily: String = "-apple-system") {
        let fullHTML: String
        if raw {
            fullHTML = htmlString
        } else {
            var sizeCss = ""
            if let size = size {
                sizeCss = "font-size: \(size)px;"
            }
            fullHTML = """
            <!doctype html>
            <html>
              <head>
                <style>
                  body {
                    font-family: \(fontFamily);
                    \(sizeCss)
                  }
                </style>
              </head>
              <body>
                \(htmlString)
              </body>
            </html>
            """
        }
        let attributedString: NSAttributedString
        if let data = fullHTML.data(using: .unicode),
           let attrString = try? NSAttributedString(data: data,
                                                    options: [.documentType: NSAttributedString.DocumentType.html],
                                                    documentAttributes: nil) {
            attributedString = attrString
        } else {
            attributedString = NSAttributedString()
        }

        self.init(attributedString)
    }

    init(_ attributedString: NSAttributedString) {
        self.init("")

        attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: []) { (attrs, range, _) in
            let string = attributedString.attributedSubstring(from: range).string
            var text = Text(string)

            if let font = attrs[.font] as? UIFont {
                text = text.font(.init(font))
            }

            if let color = attrs[.foregroundColor] as? UIColor {
                text = text.foregroundColor(Color(color))
            }

            if let kern = attrs[.kern] as? CGFloat {
                text = text.kerning(kern)
            }

            if #available(iOS 14.0, *) {
                if let tracking = attrs[.tracking] as? CGFloat {
                    text = text.tracking(tracking)
                }
            }

            if let strikethroughStyle = attrs[.strikethroughStyle] as? NSNumber, strikethroughStyle != 0 {
                if let strikethroughColor = (attrs[.strikethroughColor] as? UIColor) {
                    text = text.strikethrough(true, color: Color(strikethroughColor))
                } else {
                    text = text.strikethrough(true)
                }
            }

            if let underlineStyle = attrs[.underlineStyle] as? NSNumber,
               underlineStyle != 0 {
                if let underlineColor = (attrs[.underlineColor] as? UIColor) {
                    text = text.underline(true, color: Color(underlineColor))
                } else {
                    text = text.underline(true)
                }
            }

            if let baselineOffset = attrs[.baselineOffset] as? NSNumber {
                text = text.baselineOffset(CGFloat(baselineOffset.floatValue))
            }

            self = self + text
        }
    }
}

언급URL : https://stackoverflow.com/questions/4217820/convert-html-to-nsattributedstring-in-ios

반응형