检查字符串中的非第一个字符串实例

时间:2016-12-29 15:08:46

标签: swift string nsstring

所以,我在另一个字符串中获取字符串实例的方法是使用这个String类扩展:

func indexOf(target: String) -> Int? {

        let range = (self as NSString).range(of: target)

        guard range.toRange() != nil else {
            return nil
        }

        return range.location

    }

但是,现在我正在寻找一种方法来获取字符串中第n个字符串实例。例如,如果我想获得“House on the house House house strange people”中第3个“House”的索引。我该怎么做?

2 个答案:

答案 0 :(得分:2)

直接在Swift String上运行的可能解决方案, 没有桥接到NSString(并且没有创建临时子串):

extension String {

    func index(of target: String, instance: Int = 1) -> Int? {
        precondition(!target.isEmpty)
        precondition(instance > 0)

        var found = 0 // Number of occurrences found so far.
        var pos = startIndex // Current search position.
        // Search for next occurrence of `target`.
        while let r = range(of: target, range: pos..<endIndex) {
            found += 1
            // Are we done?
            if found == instance {
                // Distance in # of characters:
                return distance(from: startIndex, to: r.lowerBound)
            }
            // Continue search after this occurrence.
            pos = r.upperBound
        }
        return nil
    }
}

示例:

let bStr = "Houses on the show Dr. House's PlayHouse house strange people"
let ls = "House"

if let idx = bStr.index(of: ls, instance: 3) {
    print(idx) // 35
}

答案 1 :(得分:1)

我喜欢Martin R的答案,但我发现递归表达更直观。在我的实现中,我们实际返回Range(作为可选):

extension String {
    typealias SRange = Range<String.Index>
    func range(of target:String, options:String.CompareOptions, nth:Int) -> SRange? {
        func helper(hnth:Int, range:SRange) -> SRange? {
            let r = self.range(of: target, options: options, range: range)
            if let r = r, hnth < nth {
                return helper(hnth:hnth+1, range:r.upperBound..<self.endIndex)
            }
            return r
        }
        return helper(hnth:1, range: self.startIndex..<self.endIndex)
    }
}

如果目标字符串出现nth,则返回Swift Range,否则返回nil。这是一个测试:

let s = "Houses on the show House house strange people."
let targ = "House"
let r = s.range(of: targ, options: .caseInsensitive, nth: 3)
// now r is an Optional wrapping 25..<30