2016-12-29 3 views
-1

Итак, как я получаю экземпляр строки в другой строке является использование этого класса Строки расширения:Проверьте, не первый экземпляр строки в строке

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

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

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

     return range.location 

    } 

Однако, сейчас я ищу способ получить n-й экземпляр строки в строке. Например, если бы я хотел получить индекс 3-го экземпляра «Дома» в «Домах на шоу House house странные люди». Как мне это сделать?

+1

Почему вы используете NSString? Строка имеет похожие методы. – rmaddy

+0

Я не нашел метод String, который выполнил задачу поиска строки в строке, только символ в строке @maddy –

+0

_to получить индекс 3-го экземпляра «Дома» в «Дома на выставке Дом дома странных людей . Нет третьего экземпляра. «Дом» и «дом» - это две разные строки. – matt

ответ

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

«без подключения к NSString» Вы явно не указываете _cast_ в NSString, но вызываете 'range (of: range:)' вызовы в Foundation, так что, безусловно, есть мосты - это просто неявно. Я не критикую реализацию, просто оспаривая иск. – matt

+0

@matt: Вы правы, конечно. Я имел в виду явное переключение и переключение между индексами String vs. 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) 
    } 
} 

Это возвращает диапазон Swift, если 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

Никогда не думал об использовании рекурсивного подхода. Это очень продвинутый и полный ответ. Спасибо, что поделились этим со мной. –

 Смежные вопросы

  • Нет связанных вопросов^_^