Last active
December 29, 2022 09:00
-
-
Save Bigigrammer/abd36aee7457ad7e1e4cc61466221e30 to your computer and use it in GitHub Desktop.
This extension convert HTML to NSAttributedString each other. It works on Swift4.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension String { | |
func convertAttributedString() -> NSAttributedString?{ | |
let html = self._removePT() | |
let encoded = html.data(using: String.Encoding.utf8)! | |
let attributedOptions : [NSAttributedString.DocumentReadingOptionKey : Any] = [ | |
.documentType : NSAttributedString.DocumentType.html, | |
.characterEncoding : String.Encoding.utf8.rawValue | |
] | |
do { | |
let attributedTxt = try NSAttributedString(data: encoded, options: attributedOptions, documentAttributes: nil) | |
let lineHeightFixed = _fixLineHeight(attributedString: attributedTxt) | |
return lineHeightFixed | |
}catch let error as NSError { | |
print(error) | |
return nil | |
} | |
} | |
fileprivate func _removePT() -> String{ | |
let pattern = "<style(.|\n)*style>" | |
var ranges: [NSRange] = [] | |
_ = self.pregMatche(pattern: pattern, target: nil, ranges: &ranges) | |
var targets: [NSRange] = [] | |
ranges.forEach{ | |
var ranges: [NSRange] = [] | |
_ = self.pregMatche(pattern: "font\\-size: \\d*.*pt", target: $0, ranges: &ranges) | |
targets += ranges | |
} | |
let result = targets.reduce(self) { (result, range) -> String in | |
result.pregReplace(pattern: "pt", with: "px", range: range) | |
} | |
return result | |
} | |
fileprivate func _fixLineHeight(attributedString: NSAttributedString) -> NSAttributedString{ | |
let mutable = NSMutableAttributedString(attributedString: attributedString) | |
let range = NSRange(location: 0, length: mutable.string.count) | |
mutable.enumerateAttribute(.paragraphStyle, | |
in: range, | |
options: [.longestEffectiveRangeNotRequired]) | |
{ value, range, isStop in | |
if let style = value as? NSMutableParagraphStyle { | |
style.maximumLineHeight = 0 | |
style.minimumLineHeight = 0 | |
style.lineHeightMultiple = 0 | |
mutable.addAttributes([NSAttributedStringKey.paragraphStyle: style], range: range) | |
} | |
} | |
return mutable | |
} | |
fileprivate func addCSSStyle(style: String) -> String?{ | |
let pattern = "<\\/style>" | |
var range: [NSRange] = [] | |
_ = self.pregMatche(pattern: pattern, target: nil, ranges: &range) | |
guard let styleRange = range.first else {return nil} | |
let index = self.index(self.startIndex, offsetBy: styleRange.location) | |
let collection = Array(style) | |
var mutable = self | |
mutable.insert(contentsOf: collection, at: index) | |
return mutable | |
} | |
} | |
extension NSAttributedString{ | |
func convertHTML() -> String?{ | |
let newStyle = "br {display: none;}" | |
let documentAttributes: [NSAttributedString.DocumentAttributeKey : Any] = | |
[.documentType: NSAttributedString.DocumentType.html] | |
do { | |
let htmlData = try self.data(from: NSRange(location: 0, length: self.length), | |
documentAttributes: documentAttributes) | |
guard let html = String(data: htmlData, encoding: .utf8) else {return nil} | |
let removed = html._removePT() | |
return removed.addCSSStyle(style: newStyle) | |
}catch let error as NSError { | |
print(error) | |
return nil | |
} | |
} | |
} | |
// Supporting regular expression | |
extension String { | |
func pregMatche(pattern: String, target: NSRange?, options: NSRegularExpression.Options = [], ranges: inout [NSRange]) -> Bool { | |
guard let regex = try? NSRegularExpression(pattern: pattern, options: options) else { | |
return false | |
} | |
let targetStringRange = target ?? NSRange(location: 0, length: self.count) | |
let results = regex.matches(in: self, options: [], range: targetStringRange) | |
for i in 0 ..< results.count { | |
for j in 0 ..< results[i].numberOfRanges { | |
let range = results[i].range(at: j) | |
ranges.append(range) | |
} | |
} | |
return results.count > 0 | |
} | |
func pregReplace(pattern: String, with: String, range: NSRange, options: NSRegularExpression.Options = []) -> String{ | |
let regex = try! NSRegularExpression(pattern: pattern, options: options) | |
return regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: with) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@Bigigrammer do you have any idea how to manage bullet points with sub-bullet points in them?
I have one case where in the text there are a few bullet points with sub-bullet points in it. After converting it from HTML string to NSAttributed sub-bullet point alignment gets changed.
Let me know if you have any solution for that