Color all occurrences of string in swift

不羁岁月 提交于 2019-11-26 12:31:29

问题


This code

var textSearch=\"hi\"
var textToShow=\"hi hihi hi\" 
var rangeToColor = (textToShow as NSString).rangeOfString(textSearch)
var attributedString = NSMutableAttributedString(string:textToShow)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.yellowColor() , range: rangeToColor)
TextView.attributedText=attributedString

gives me NSRange to color a string inside the TextView. The problem is that I only returns the first occurrence. If the word contains \"hi hihi hi\" only the first \"hi\" is colored. How can I get all occurrences of the string?


回答1:


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



回答2:


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



回答3:


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
}



回答4:


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



回答5:


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 */)



回答6:


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


来源:https://stackoverflow.com/questions/27180184/color-all-occurrences-of-string-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!