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

Swift 检查字符串中字符串的非第一个实例,swift,string,nsstring,Swift,String,Nsstring,因此,我在另一个字符串中获取字符串实例的方法是使用以下字符串类扩展: func indexOf(target: String) -> Int? { let range = (self as NSString).range(of: target) guard range.toRange() != nil else { return nil } return range.location }

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

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 show House House Strights people”中“House”的第三个实例的索引。我该怎么做呢?

一种可能的解决方案,它直接在Swift
字符串上运行,
不桥接到
NSString
(并且不创建临时子字符串):


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


为什么要使用NSString?String有类似的方法。我没有找到一个String方法来完成在字符串中查找字符串的任务,只有String@maddy中的一个字符来获取“House on the show House House Strangle people”中“House”的第三个实例的索引。没有第三个实例<代码>“House”
“House”
是两个不同的字符串。我还没有找到一个字符串方法来完成在字符串
范围(of:options:range:locale:)中查找字符串的任务。
直接作用于Swift字符串。@matt的修复方法是将它们都转换为小写,然后继续执行任务。“不桥接到NSString”您不会显式地强制转换到NSString,而是调用
range(of:range:)调用基础,所以肯定是桥接-它只是隐含的。我不是在批评实现,只是在争论这个说法。“马特:你当然是对的。我的意思是在字符串和NString索引之间明确的桥接和跳跃。这是一个非常高级和完整的答案。谢谢你和我分享。
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
}
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)
    }
}
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