Color all occurrences of string in swift

前端 未结 6 1039
旧巷少年郎
旧巷少年郎 2020-11-29 11:33

This code

var textSearch=\"hi\"
var textToShow=\"hi hihi hi\" 
var rangeToColor = (textToShow as NSString).rangeOfString(textSearch)
var attributedString =          


        
相关标签:
6条回答
  • 2020-11-29 11:33

    I made those two methods to either color for only once occurrence or color all the occurrence for that text:

    extension NSMutableAttributedString{
        func setColorForText(_ textToFind: String, with color: UIColor) {
            let range = self.mutableString.range(of: textToFind, options: .caseInsensitive)
            if range.location != NSNotFound {
                addAttribute(NSForegroundColorAttributeName, value: color, range: range)
            }
        }
    
        func setColorForAllOccuranceOfText(_ textToFind: String, with color: UIColor) {
            let inputLength = self.string.count
            let searchLength = textToFind.count
            var range = NSRange(location: 0, length: self.length)
    
            while (range.location != NSNotFound) {
                range = (self.string as NSString).range(of: textToFind, options: [], range: range)
                if (range.location != NSNotFound) {
                    self.addAttribute(NSForegroundColorAttributeName, value: color, range: NSRange(location: range.location, length: searchLength))
                    range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 11:43

    Swift 5

    let attrStr = NSMutableAttributedString(string: "hi hihi hey")
    let inputLength = attrStr.string.count
    let searchString = "hi"
    let searchLength = searchString.characters.count
    var range = NSRange(location: 0, length: attrStr.length)
    
    while (range.location != NSNotFound) {
        range = (attrStr.string as NSString).range(of: searchString, options: [], range: range)
        if (range.location != NSNotFound) {
            attrStr.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.yellow, range: NSRange(location: range.location, length: searchLength))
            range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
        }
    }
    

    Swift 3

    let attrStr = NSMutableAttributedString(string: "hi hihi hey")
    let inputLength = attrStr.string.characters.count
    let searchString = "hi"
    let searchLength = searchString.characters.count
    var range = NSRange(location: 0, length: attrStr.length)
    
    while (range.location != NSNotFound) {
        range = (attrStr.string as NSString).range(of: searchString, options: [], range: range)
        if (range.location != NSNotFound) {
            attrStr.addAttribute(NSForegroundColorAttributeName, value: UIColor.yellow(), range: NSRange(location: range.location, length: searchLength))
            range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
        }
    }
    

    Swift 2

    let attrStr = NSMutableAttributedString(string: "hi hihi hey")
    let inputLength = attrStr.string.characters.count
    let searchString = "hi"
    let searchLength = searchString.characters.count
    var range = NSRange(location: 0, length: attrStr.length)
    
    while (range.location != NSNotFound) {
        range = (attrStr.string as NSString).rangeOfString(searchString, options: [], range: range)
        if (range.location != NSNotFound) {
            attrStr.addAttribute(NSForegroundColorAttributeName, value: UIColor.yellowColor(), range: NSRange(location: range.location, length: searchLength))
            range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
        }
    }
    
    0 讨论(0)
  • 2020-11-29 11:47

    Syntax sugar for Kevin's answer above.

    Called like:

    attrStr.attributeRangeFor(searchString, attributeValue: UIColor.yellowColor(), atributeSearchType: .All)
    

    Swift 2.0:

    import UIKit
    
    extension NSMutableAttributedString {
        enum AtributeSearchType {
            case First, All, Last
        }
    
        func attributeRangeFor(searchString: String, attributeValue: AnyObject, atributeSearchType: AtributeSearchType) {
            let inputLength = self.string.characters.count
            let searchLength = searchString.characters.count
            var range = NSRange(location: 0, length: self.length)
            var rangeCollection = [NSRange]()
    
            while (range.location != NSNotFound) {
                range = (self.string as NSString).rangeOfString(searchString, options: [], range: range)
                if (range.location != NSNotFound) {
                    switch atributeSearchType {
                    case .First:
                        self.addAttribute(NSForegroundColorAttributeName, value: attributeValue, range: NSRange(location: range.location, length: searchLength))
                        return
                    case .All:
                        self.addAttribute(NSForegroundColorAttributeName, value: attributeValue, range: NSRange(location: range.location, length: searchLength))
                        break
                    case .Last:
                        rangeCollection.append(range)
                        break
                    }
    
                    range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
                }
            }
    
            switch atributeSearchType {
            case .Last:
                let indexOfLast = rangeCollection.count - 1
                self.addAttribute(NSForegroundColorAttributeName, value: attributeValue, range: rangeCollection[indexOfLast])
                break
            default:
                break
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 11:47

    Using NSRegularExpression saves you from doing all the range calculations on by yourself. This example also will highlight two words instead of just one.

    let text = "If you don't have a plan, you become part of somebody else's plan."
    let toHighlight = ["plan", "you"]
    let range = text.nsRange(from: text.startIndex ..< text.endIndex) // full text
    
    let rangesToHighlight: [[NSRange]] = toHighlight.map { search in
        do {
            let regex = try NSRegularExpression(pattern: search, options: [])
            let matches: [NSTextCheckingResult] = regex.matches(in: text, options: [], range: range)
            return matches.map { $0.range } // get range from NSTextCheckingResult
        } catch {
            return [NSRange]()
        }
    }
    
    let yellow = UIColor.yellow
    let attributedText = NSMutableAttributedString(string: text)
    
    let flattenedRanges: [NSRange] = rangesToHighlight.joined()
    flattenedRanges.forEach { // apply color to all ranges
        attributedText.addAttribute(NSForegroundColorAttributeName,
                                    value: yellow,
                                    range: $0)
    }
    
    0 讨论(0)
  • Swift 4:

    let string = "foo fbar foofoo foofo"
    let mutableAttributedString = NSMutableAttributedString(string: string)
    let searchString = "foo"
    var rangeToSearch = string.startIndex..<string.endIndex
    while let matchingRange = string.range(of: searchString, options: [], range: rangeToSearch) {
      mutableAttributedString.addAttribute(.foregroundColor, value: UIColor.yellow, range: NSRange(matchingRange, in: string))
      rangeToSearch = matchingRange.upperBound..<string.endIndex
    }
    
    0 讨论(0)
  • 2020-11-29 12:00

    I’ve created an Extension for it in swift 4.2

    extension NSMutableAttributedString {
    // Adds attributes EVERY TIME the text to change appears
    func addAttributes(_ attributes: [NSAttributedString.Key: NSObject], forText text: String) {
        var range = NSRange(location: 0, length: self.length)
        while (range.location != NSNotFound) {
            range = (self.string as NSString).range(of: text, options: [], range: range)
            if (range.location != NSNotFound) {
                self.addAttributes(attributes, range: NSRange(location: range.location, length: text.count))
                range = NSRange(location: range.location + range.length, length: self.string.count - (range.location + range.length))
            }
        }
    }
    

    Now you can call it like this:

    let attributedString = NSMutableAttributedString(attributedString: textView.attributedText)
    let myAttributes = [/* your attributes here */]
    attributedString.addAttributes(myAttributes, forText: /* your text here */)
    
    0 讨论(0)
提交回复
热议问题