简体   繁体   English

快速获取字符串中子字符串的所有范围

[英]get all ranges of a substring in a string in swift

I have a string for example "ab ad adk fda kla kad ab ab kd".我有一个字符串,例如“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我想获得 ab 的所有范围。(这里 ab 出现在 3 个位置,所以我应该得到 3 个范围)。在正常情况下,我的代码工作正常,但如果搜索文本是“.”,那么我得到的结果是错误的

do {
    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 {
    ...
}

The following solution uses the native Swift 4 function range(of:, options:, range:, locale:) ):以下解决方案使用原生 Swift 4 函数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 ) (然后 Swift 4 提供了原生 API 来从Range<Index>转换为NSRange

Swift 5:斯威夫特 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
    }
}

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 ).除了主要问题,这段代码还展示了将NSRangeRange<String.Index>相互转换的方法(基于这篇文章)。

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:如果您正在搜索子字符串,我建议改用旧的 rangeOf... 方法:

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.只需继续在您的字符串上调用该方法(并调整searchRange ),直到找不到更多匹配项。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM