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

时间:2016-04-26 12:48:01

标签: ios swift matching

我有一个字符串,例如“ab ad adk fda kla kad ab ab kd”。我希望获得所有范围的ab。(这里ab出现在3个位置,所以我应该得到3个范围)。在正常的情况下我的代码工作正常,但如果搜索文本是“。”,那么我得到错误的结果< / p>

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

5 个答案:

答案 0 :(得分:11)

以下解决方案使用原生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然后提供原生API以便从Range<Index>转换为NSRange

答案 1 :(得分:3)

我会建议这样的解决方案:

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

除了主要问题,此代码还显示了将NSRange转换为Range<String.Index>的方法(基于this post)。

答案 2 :(得分:1)

您正在使用正则表达式,因此您需要注意具有特殊含义的字符 - .只是其中之一。

如果您正在搜索子字符串,我建议使用旧的rangeOf ...方法代替:

func rangeOfString(_ searchString: String,
           options mask: NSStringCompareOptions,
             range searchRange: NSRange) -> NSRange

只需在字符串上调用该方法(并调整searchRange),直到找不到更多匹配项。

答案 3 :(得分:1)

快捷键5:

最受欢迎答案的改进版本:

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

答案 4 :(得分:0)

您可以通过以下代码获取特定字符串的出现次数:

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