UITextView highlight all matches using swift

2020-02-03 08:28发布

问题:

I want to highlight all matches word with searching. I wrote code but I couldn't use a loop. When i search a word, my app find words and highlight only first word. here is my code

var count = 0
let attributedText = NSMutableAttributedString(attributedString: txtMetin2.attributedText)
let text2 = txtArama.text as NSString
let text = txtMetin2.text as NSString
var range:NSRange
var checker:NSString = ""

for(var i=0 ; i<text.length - text2.length-1 ; i++)
{        
    range = NSMakeRange(i, text2.length)
    checker = text.substringWithRange(range)
    if(text2 == checker)
    {
        count++    
        let highlightedRange = text.rangeOfString("\(text2)")
        attributedText.addAttribute(NSBackgroundColorAttributeName, value: UIColor.blueColor(), range: highlightedRange)
        let textAttachment = NSTextAttachment()
        let textAttachmentString = NSAttributedString(attachment: textAttachment)
        attributedText.appendAttributedString(textAttachmentString)
        txtMetin2.attributedText = attributedText                               
    }
}
println("\(count)")

i am very new at swift. sorry for bad coding. my codes find matches count but how can i highlight all matches thank you

回答1:

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
}


回答2:

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


回答3:

Uitextview highlight all matches word swift 3.0

 let searchString = "Lorem Ipsum"
 let baseString = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard .Containing LOREM IPSUM passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem IPSUM"



let attributed = NSMutableAttributedString(string: baseString)
    do
    {
        let regex = try! NSRegularExpression(pattern: searchString,options: .caseInsensitive)
        for match in regex.matches(in: baseString, options: NSRegularExpression.MatchingOptions(), range: NSRange(location: 0, length: baseString.characters.count)) as [NSTextCheckingResult] {
            attributed.addAttribute(NSBackgroundColorAttributeName, value: UIColor.yellow, range: match.range)
        }
        self.txtView.attributedText = attributed
    }

click here to see image



回答4:

Improved customized solution for Swift 4.2

extension NSAttributedString {
    convenience init(base: String,
                     keyWords: [String],
                     foregroundColor: UIColor,
                     font: UIFont,
                     highlightForeground: UIColor,
                     highlighBackground: UIColor) {
        let baseAttributed = NSMutableAttributedString(string: base, attributes: [NSAttributedString.Key.font: font,
                                                                                  NSAttributedString.Key.foregroundColor: foregroundColor])
        let range = NSRange(location: 0, length: base.utf16.count)
        for word in keyWords {
            guard let regex = try? NSRegularExpression(pattern: word, options: .caseInsensitive) else {
                continue
            }

            regex
                .matches(in: base, options: .withTransparentBounds, range: range)
                .forEach { baseAttributed
                    .addAttributes([NSAttributedString.Key.backgroundColor: highlighBackground,
                                    NSAttributedString.Key.foregroundColor: highlightForeground],
                                   range: $0.range) }
        }
        self.init(attributedString: baseAttributed)
    }
}


回答5:

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


回答6:

Solved.

this is new :

var count = 0
let attributedText = NSMutableAttributedString(attributedString: txtMetin2.attributedText)
let text2 = txtArama.text as NSString
let text = txtMetin2.text as NSString
println("\(text.length)")
println("\(text2.length)")
var range:NSRange
var checker:NSString = ""

for(var i=0 ; i <= text.length - text2.length ; i++)
{
    range = NSMakeRange(i, text2.length)
    checker = text.substringWithRange(range)
    if(text2 == checker)
    {
        attributedText.addAttribute(NSBackgroundColorAttributeName, value: UIColor.yellowColor(),
            range: range)
        let textAttachment = NSTextAttachment()
        let textAttachmentString = NSAttributedString(attachment: textAttachment)
        attributedText.appendAttributedString(textAttachmentString)
        txtMetin2.attributedText = attributedText
        count++
    }
}
println("\(count)")

i used range variable instead of highlighted range in attributedText.addAtrribute()