Search code examples
swiftnsrange

function to find all NSRanges for a string in string in swift


I would like to have all CG letters pairs in red color in DNA sequences (string). I can do it by using NSMutableAttributedString. For this I need NSRanges of all CG positions and I have tried to make the function below but in the line

indexesOfStringIn = (stringOut as NSString).rangeOfString(stringIn, options: 0, range: rangeForIndexStringIn) 

rangeOfString with range cannot be invoked with an argument list of type (String, options: Int, range: NSRange). Where is a mistake ? What i did wrong ?

func searchForNSRangesOfStringInString(stringOut: String, stringIn: String) -> [NSRange]

{
    var arrayOfindexesOfStringIn = [NSRange]()

if stringIn.characters.count > 1
{
    var rangeNS = (stringOut as NSString).rangeOfString(stringIn)

    if rangeNS.location != NSNotFound
    {
        let endIndexOfStringOut = (stringOut as NSString).length - 1
        var indexesOfStringIn = (stringOut as NSString).rangeOfString(stringIn)
        arrayOfindexesOfStringIn = [indexesOfStringIn]
        var lastIndexOfStringIn = (stringOut as NSString).rangeOfString(stringIn).location
        var rangeForIndexStringIn = NSRange(lastIndexOfStringIn...endIndexOfStringOut)

        while indexesOfStringIn.location != NSNotFound
        {
            indexesOfStringIn = (stringOut as NSString).rangeOfString(stringIn, options: 0, range: rangeForIndexStringIn)

            if indexesOfStringIn.location != NSNotFound
            {

                arrayOfindexesOfStringIn.append(indexesOfStringIn)

                lastIndexOfStringIn = (stringOut as NSString).rangeOfString(stringIn, options: 0, range: rangeForIndexStringIn).location

                rangeForIndexStringIn = NSRange(lastIndexOfStringIn...endIndexOfStringOut)

            }
        }
    }
}
return arrayOfindexesOfStringIn
} 

Solution

  • As suggested by uchuugaka it is much easier to use NSRegularExpression to return an array of the matches ranges in a string as follow:

    extension String {
        func findOccurencesOf(text text:String) -> [NSRange] {
            return !text.isEmpty ? try! NSRegularExpression(pattern: text, options: []).matchesInString(self, options: [], range: NSRange(0..<characters.count)).map{ $0.range } : []
        }
    }
    
    let str = "CGCGCGCGCG"
    
    let ranges = str.findOccurencesOf(text: "CG")
    
    print(ranges.count)   // 5
    

    Just add a control event for your textField Editing changed and loop through the ranges as follow:

    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var textField: UITextField!
        override func viewDidLoad() {
            super.viewDidLoad()
            textField.addTarget(self, action: "coloring:", forControlEvents: UIControlEvents.EditingChanged)
            textField.becomeFirstResponder()
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
        func coloring(sender:UITextField) {
            let attText = NSMutableAttributedString(string: sender.text ?? "")
            let ranges = sender.text!.uppercaseString.findOccurencesOf(text: "CG")
            for range in ranges {
                attText.addAttributes([NSForegroundColorAttributeName : UIColor.redColor()], range: range)
            }
            sender.attributedText = attText
        }
    
    }
    
    extension String {
        func findOccurencesOf(text text:String) -> [NSRange] {
            return !text.isEmpty ? try! NSRegularExpression(pattern: text, options: []).matchesInString(self, options: [], range: NSRange(0..<characters.count)).map{ $0.range } : []
        }
    }