UITextView highlight all matches using swift

Swift 4 & 5

func generateAttributedString(with searchTerm: String, targetString: String) -> NSAttributedString? {

    let attributedString = NSMutableAttributedString(string: targetString)
    do {
        let regex = try NSRegularExpression(pattern: searchTerm.trimmingCharacters(in: .whitespacesAndNewlines).folding(options: .diacriticInsensitive, locale: .current), options: .caseInsensitive)
        let range = NSRange(location: 0, length: targetString.utf16.count)
        for match in regex.matches(in: targetString.folding(options: .diacriticInsensitive, locale: .current), options: .withTransparentBounds, range: range) {
            attributedString.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.bold), range: match.range)
        }
        return attributedString
    } catch {
        NSLog("Error creating regular expresion: \(error)")
        return nil
    }
}

you can use the following function passing the search input and the current content. that will return a NSAttributedString? that you can set in your TextView

Swift 3

func generateAttributedString(with searchTerm: String, targetString: String) -> NSAttributedString? {
    let attributedString = NSMutableAttributedString(string: targetString)
    do {
        let regex = try NSRegularExpression(pattern: searchTerm, options: .caseInsensitive)
        let range = NSRange(location: 0, length: targetString.utf16.count)
        for match in regex.matches(in: targetString, options: .withTransparentBounds, range: range) {
            attributedString.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 16, weight: UIFontWeightBold), range: match.range)
        }
        return attributedString
    } catch _ {
        NSLog("Error creating regular expresion")
        return nil
    }
}

Edit:

highlight with diacritic insensitive option:

func generateAttributedString(with searchTerm: String, targetString: String) -> NSAttributedString? {

    let attributedString = NSMutableAttributedString(string: targetString)
    do {
        let regex = try NSRegularExpression(pattern: searchTerm.trimmingCharacters(in: .whitespacesAndNewlines).folding(options: .diacriticInsensitive, locale: .current), options: .caseInsensitive)
        let range = NSRange(location: 0, length: targetString.utf16.count)
        for match in regex.matches(in: targetString.folding(options: .diacriticInsensitive, locale: .current), options: .withTransparentBounds, range: range) {
            attributedString.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 16, weight: UIFontWeightBold), range: match.range)
        }
        return attributedString
    } catch {
        NSLog("Error creating regular expresion: \(error)")
        return nil
    }
}

I want to little improve the solution provided by @Barath and @Bruno Paulino, as this solution won't work with escaped characters like {}[]()'", this solution works with escaped characters, this solution written in SWIFT 5.

func generateAttributedString(with searchTerm: String, targetString: NSAttributedString) -> NSAttributedString? {
    let attributedString = NSMutableAttributedString(attributedString: targetString)
    do {

        let regex = try NSRegularExpression(pattern:  NSRegularExpression.escapedPattern(for: searchTerm).trimmingCharacters(in: .whitespacesAndNewlines).folding(options: .regularExpression, locale: .current), options: .caseInsensitive)
        let range = NSRange(location: 0, length: targetString.string.utf16.count)
        attributedString.addAttribute(NSAttributedString.Key.backgroundColor, value: UIColor.clear, range: range)
        for match in regex.matches(in: targetString.string.folding(options: .regularExpression, locale: .current), options: .withTransparentBounds, range: range) {
            attributedString.addAttribute(NSAttributedString.Key.backgroundColor, value: UIColor.yellow, range: match.range)
        }
        return attributedString
    } catch {
        NSLog("Error creating regular expresion: \(error)")
        return nil
    }
}

Obligatory NSRegularExpression based solution.

let searchString = "this"
let baseString = "This is some string that contains the word \"this\" more than once. This substring has multiple cases. ThisthisThIs."

let attributed = NSMutableAttributedString(string: baseString)

var error: NSError?
let regex = NSRegularExpression(pattern: searchString, options: .CaseInsensitive, error: &error)

if let regexError = error {
    println("Oh no! \(regexError)")
} else {
    for match in regex?.matchesInString(baseString, options: NSMatchingOptions.allZeros, range: NSRange(location: 0, length: baseString.utf16Count)) as [NSTextCheckingResult] {
        attributed.addAttribute(NSBackgroundColorAttributeName, value: UIColor.yellowColor(), range: match.range)
    }

    textView.attributedText = attributed
}