Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find all positions of one string in another string in swift2 ?

Tags:

string

swift

I can find first position of string "ATG" in myString "ATGGACGTGAGCTGATCGATGGCTGAAATGAAAA" (i.e. index range is 0..<3) by using code below. Question is how to find all positions of "ATG", not only the first one in the myString.

let stringRange = myString.rangeOfString("ATG")
like image 829
VYT Avatar asked Aug 29 '15 11:08

VYT


People also ask

How do I check if a string contains another string in Swift?

Swift String contains() The contains() method checks whether the specified string (sequence of characters) is present in the string or not.

How do you find the position of a character in a string in Swift?

In swift, we can use the firstIndex(of:) method to get the index position of a character in a given string.

What is Nsrange in Swift?

A structure used to describe a portion of a series, such as characters in a string or objects in an array.

What is substring Swift?

Substrings. When you get a substring from a string—for example, using a subscript or a method like prefix(_:) —the result is an instance of Substring , not another string. Substrings in Swift have most of the same methods as strings, which means you can work with substrings the same way you work with strings.


2 Answers

You can use NSRegularExpression to find all occurrences of your string:

Swift 1.2:

let mystr = "ATGGACGTGAGCTGATCGATGGCTGAAATGAAAA"
let searchstr = "ATG"
let ranges: [NSRange]

// Create the regular expression.
if let regex = NSRegularExpression(pattern: searchstr, options: nil, error: nil) {
    // Use the regular expression to get an array of NSTextCheckingResult.
    // Use map to extract the range from each result.
    ranges = regex.matchesInString(mystr, options: nil, range: NSMakeRange(0, count(mystr))).map {$0.range}

} else {
    // There was a problem creating the regular expression
    ranges = []
}

println(ranges)  // prints [(0,3), (18,3), (27,3)]

Swift 2:

let mystr = "ATGGACGTGAGCTGATCGATGGCTGAAATGAAAA"
let searchstr = "ATG"
let ranges: [NSRange]

do {
    // Create the regular expression.
    let regex = try NSRegularExpression(pattern: searchstr, options: [])

    // Use the regular expression to get an array of NSTextCheckingResult.
    // Use map to extract the range from each result.
    ranges = regex.matchesInString(mystr, options: [], range: NSMakeRange(0, mystr.characters.count)).map {$0.range}
}
catch {
    // There was a problem creating the regular expression
    ranges = []
}

print(ranges)  // prints [(0,3), (18,3), (27,3)]

Swift 3: using Swift's native Range type.

let mystr = "ATGGACGTGAGCTGATCGATGGCTGAAATGAAAA"
let searchstr = "ATG"

do {
    // Create the regular expression.
    let regex = try NSRegularExpression(pattern: searchstr, options: [])

    // Use the regular expression to get an array of NSTextCheckingResult.
    // Use map to extract the range from each result.
    let fullStringRange = mystr.nsRange(from: mystr.startIndex ..< mystr.endIndex)          
    let matches = regex.matches(in: mystr, options: [], range: fullStringRange)
    let ranges = matches.map {$0.range}
    print(ranges)  // prints [(0,3), (18,3), (27,3)]
}
catch {}

Notes:

  • This method has its limitations. You'll be fine if the string you are searching for is simple text, but if the string contains symbols (such as "+*()[].{}?\^$") which have special meaning in a regular expression, then this will not work as expected. You could preprocess the search string to add escapes to nullify the special meanings of those characters, but this is probably more trouble than it is worth.
  • Another limitation can be demonstrated when mystr is "AAAA" and searchstr is "AA". In this case, the string will only be found twice. The middle AA will not be found because it starts with a character that is part of the first range.
like image 125
vacawama Avatar answered Nov 13 '22 15:11

vacawama


extension String {
    public func rangesOfString(searchString:String, options: NSStringCompareOptions = [], searchRange:Range<Index>? = nil ) -> [Range<Index>] {
        if let range = rangeOfString(searchString, options: options, range:searchRange) {

            let nextRange = Range(start:range.endIndex, end:self.endIndex)
            return [range] + rangesOfString(searchString, searchRange: nextRange)
        } else {
            return []
        }
    }
}
like image 28
Klaas Avatar answered Nov 13 '22 16:11

Klaas