2016-12-29 20 views
-1

内の文字列の非最初のインスタンスだから、私は別の文字列に文字列のインスタンスを取得されている方法は、この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 House"の3番目のインスタンスのインデックスを "Show house house house strange people。"で取得したい場合、どうすればいい?

+1

なぜNSStringを使用していますか?文字列にも同様のメソッドがあります。 – rmaddy

+0

文字列内の文字列を検索するタスクを達成した文字列メソッドが見つかりませんでした@maddy –

+0

_ "House"の3番目のインスタンスのインデックスを取得するハウスハウスの不思議な人々 "_第3の例はありません。 '' House''と '' house''は2つの異なる文字列です。 – matt

答えて

2

(一時的な部分文字列と作成せず)NSStringに橋渡しすることなく、スウィフトString、 上で直接動作可能な解決策:

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

"NSStringへのブリッジなし" NSStringに対して明示的に_cast_しませんが、 'range(of:range:)'を呼び出すとFoundationが呼び出されるので、確かにブリッジングが行われます。私は実装を批判しておらず、主張に異議を唱えるだけです。 – matt

+0

@matt:あなたはもちろんそうです。私が意味することは、明示的なブリッジングとNSStringインデックスとの間のジャンプです。最終的な範囲をIntに変換する唯一の理由は、OPが探すものであるためです。 –

1

私はマーティン・Rの答えを言っていますが、より直感的な再帰式が見つかりました。

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発生が存在する場合スウィフト範囲を返し、そうでない場合は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 
+0

再帰的アプローチを使用することは考えていません。これは非常に高度で完全な答えです。これを私と共有してくれてありがとう。 –

関連する問題