1

For eg. replace a <strong> tag with bold font. So that it can be applied as attributed text to label, textfield or textview

Larme
  • 24,190
  • 6
  • 51
  • 81
Jagadeeshwar
  • 863
  • 11
  • 25

3 Answers3

1
extension NSAttributedString {

    func replaceHTMLTag(tag: String, withAttributes attributes: [String: AnyObject]) -> NSAttributedString {
        let openTag = "<\(tag)>"
        let closeTag = "</\(tag)>"

        let resultingText: NSMutableAttributedString = self.mutableCopy() as! NSMutableAttributedString
        while true {
            let plainString = resultingText.string as NSString
            let openTagRange = plainString.range(of: openTag)
            if openTagRange.length == 0 {
                break
            }

            let affectedLocation = openTagRange.location + openTagRange.length

            let searchRange = NSRange(location: affectedLocation, length: plainString.length - affectedLocation)

            let closeTagRange = plainString.range(of: closeTag, options: NSString.CompareOptions.init(rawValue: 0), range: searchRange)

            resultingText.setAttributes(attributes, range: NSRange(location: affectedLocation, length: closeTagRange.location - affectedLocation))
            resultingText.deleteCharacters(in: closeTagRange)
            resultingText.deleteCharacters(in: openTagRange)
        }
        return resultingText as NSAttributedString
    }
}
Jagadeeshwar
  • 863
  • 11
  • 25
  • I am receiving the following error with Xcode9(Swift4): Cannot convert value of type '[String : AnyObject]' to expected argument type '[NSAttributedStringKey : Any]?' Solved with: https://stackoverflow.com/questions/45695286/cannot-convert-value-of-type-string-anyobject-to-expected-argument-type – Dorad Oct 01 '17 at 15:49
1

You need to remove the ^ and $ anchors.

The ^ means start of string and $ means end of string (or line, depending on the options). That's why your first example works: in the first test string, the start of the string is really followed by your pattern and ends with it.

In the second test string, the pattern is found in the middle of the string, thus the ^... can't apply. If you would just remove the ^, the $ would apply on the second occurrence of the registration number and the output would be my car reg 1 - DD11 AAA my car reg 2 - XX.

let myString = "my car reg 1 - DD11 AAA  my car reg 2 - AA22 BBB"
let regex = try! NSRegularExpression(pattern: "([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}", options:        NSRegularExpressionOptions.CaseInsensitive)
let range = NSMakeRange(0, myString.characters.count)
let modString = regex.stringByReplacingMatchesInString(myString, options: [], range: range, withTemplate: "XX")
print(modString)
// Output: "my car reg 1 - XX  my car reg 2 - XX"

Reference: https://stackoverflow.com/a/28503676/8169585

Linar sen
  • 93
  • 1
  • 1
  • 5
1

Try this extension. It will convert HTML string into NSAttributtedString. I also has the 0.75 ratio applied because of the fact that the default conversion increases all the font size

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 }
        html.beginEditing()
        html.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, html.length), options: .init(rawValue: 0)) {
            (value, range, stop) in
            if let font = value as? UIFont {
                let resizedFont = font.withSize(font.pointSize * 0.75)
                html.addAttribute(NSFontAttributeName,
                                         value: resizedFont,
                                         range: range)
            }
        }
        html.endEditing()
        return html
    }
}
Fangming
  • 24,551
  • 6
  • 100
  • 90