I have a string for example \"ab ad adk fda kla kad ab ab kd\". I want to get all range of ab.(Here ab is present at 3 position so I should get 3 range).In normal scenarion
Swift 5:
The improved version of the most popular answer:
extension String {
func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range<Index>] {
var ranges: [Range<Index>] = []
while let range = range(of: substring, options: options, range: (ranges.last?.upperBound ?? self.startIndex)..<self.endIndex, locale: locale) {
ranges.append(range)
}
return ranges
}
}
You are using regular expressions, so you need to take care about characters that have special meaning - .
is only one of them.
If you're doing a search for substrings, I suggest to use the good old rangeOf... methods instead:
func rangeOfString(_ searchString: String,
options mask: NSStringCompareOptions,
range searchRange: NSRange) -> NSRange
Just keep calling that method on your string (and adjust the searchRange
), until no further matches are found.
The following solution uses the native Swift 4 function range(of:, options:, range:, locale:)
):
extension String {
func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range<Index>] {
var ranges: [Range<Index>] = []
while ranges.last.map({ $0.upperBound < self.endIndex }) ?? true,
let range = self.range(of: substring, options: options, range: (ranges.last?.upperBound ?? self.startIndex)..<self.endIndex, locale: locale)
{
ranges.append(range)
}
return ranges
}
}
(Swift 4 then provides native API to convert from Range<Index>
to NSRange
)
I would suggest such a solution:
import Foundation
extension String {
func rangesOfString(s: String) -> [Range<Index>] {
let re = try! NSRegularExpression(pattern: NSRegularExpression.escapedPatternForString(s), options: [])
return re.matchesInString(self, options: [], range: nsRange(startIndex ..< endIndex)).flatMap { range($0.range) }
}
func range(nsRange : NSRange) -> Range<Index>? {
let utf16from = utf16.startIndex.advancedBy(nsRange.location, limit: utf16.endIndex)
let utf16to = utf16from.advancedBy(nsRange.length, limit: utf16.endIndex)
if let from = String.Index(utf16from, within: self),
let to = String.Index(utf16to, within: self)
{
return from ..< to
} else {
return nil
}
}
func nsRange(range : Range<Index>) -> NSRange {
let utf16from = String.UTF16View.Index(range.startIndex, within: utf16)
let utf16to = String.UTF16View.Index(range.endIndex, within: utf16)
return NSRange(location: utf16.startIndex.distanceTo(utf16from), length: utf16from.distanceTo(utf16to))
}
}
print("[^x]? [^x]? [^x]?".rangesOfString("[^x]?")) // [Range(0..<5), Range(6..<11), Range(12..<17)]
Aside the main question, this code also shows the way to convert NSRange
to and from Range<String.Index>
(based on this post).
You can get occurance count for particular string by following code:
let str: NSMutableString = "ab ad adk fda kla kad ab ab kd"
let count = str.replaceOccurrencesOfString("ab", withString: "ab", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, str.length))