Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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 my code is working fine, but if search text is ".",then I am getting wrong result

let regEx = try NSRegularExpression(pattern: searchText, options: NSRegularExpressionOptions.CaseInsensitive) let matchesRanges = regEx.matchesInString(attributedText.string, options:[], range: NSMakeRange(0, attributedText.string.length)) for rng in matchesRanges { let wordRange = rng.rangeAtIndex(0) } catch { Do you know what regular expressions are? This is not plain old character-by-character string search... Eiko Apr 26, 2016 at 13:20

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)

This can result in an infinite loop in some situations when using a regular expression. Check this answer on how to avoid it stackoverflow.com/a/32306142/2303865 – Leo Dabus Mar 4, 2018 at 1:23 @LeoDabus I've identified one case where that could happen, as indeed some regular expression will return a valid range, even if the range to search in is empty. I've updated the code to reflect that. If that was not your original issue, would you mind sharing the regex that caused the issue? – Stéphane Copin Feb 6, 2019 at 17:40 If I remember correctly it happens if there is an empty range in the end of the string. Sorry but the question/regex I couldn't find. – Leo Dabus Feb 6, 2019 at 18:37
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
    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).

I use NSRegularExpression.escapedPatternForString() to escape any possible pattern metacharacters. This must be a reliable solution. – werediver Apr 26, 2016 at 13:57

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.

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

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.