get all ranges of a substring in a string in swift

后端 未结 5 1332
时光说笑
时光说笑 2020-12-11 20:14

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

相关标签:
5条回答
  • 2020-12-11 20:31

    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
        }
    }
    
    0 讨论(0)
  • 2020-12-11 20:32

    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.

    0 讨论(0)
  • 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)

    0 讨论(0)
  • 2020-12-11 20:43

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

    0 讨论(0)
  • 2020-12-11 20:44

    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))
    
    0 讨论(0)
提交回复
热议问题