The compleate solution
extension NSAttributedString {
func replacingOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) -> NSAttributedString {
let s = NSMutableAttributedString(attributedString: self)
s.beginEditing()
s.replaceOccurrences(of: target, with: replacement, attributes: attributes)
s.endEditing()
return s
}
}
extension NSMutableAttributedString {
func replaceOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) {
var searchRange = NSRange(location: 0, length: self.length)
while let range = self.string.range(of: target, options: [], range: Range(searchRange, in: self.string)) {
let nsRange = NSRange(range, in: self.string)
self.replaceCharacters(in: nsRange, with: replacement)
let newRange = NSRange(location: nsRange.location, length: replacement.count)
if let attributes = attributes {
self.addAttributes(attributes, range: newRange)
}
searchRange = NSRange(location: newRange.upperBound, length: self.length - newRange.upperBound)
}
}
}