2015-07-31 4 views
21

Моя основная строка: «hello Swift Swift and Swift» и подстрока Swift. Мне нужно получить количество раз, когда подстрока «Swift» встречается в указанной строке.Swift :: Количество вхождений подстроки в строке

Этот код может определять, существует ли разрыв. вар строка = «привет Swift Swift и Swift»

if string.rangeOfString("Swift") != nil{ 
println("exists") 
} 

Теперь мне нужно знать количество возникновения.

ответ

49

Простой подход был бы разделить на "Swift", и вычитаем 1 из количества деталей:

let s = "hello Swift Swift and Swift" 
let tok = s.components(separatedBy:"Swift") 
print(tok.count-1) 

Этот код печатает 3.

Edit: Перед Swift 3 syntax код выглядел следующим образом :

let tok = s.componentsSeparatedByString("Swift") 
+0

Привет, так как многие многие другие ответы указывают, если строка начинается с "Swift", этот код не будет работать. (отключена на одну ошибку) Я пытаюсь получить простую реализацию для этого, но пока что все еще не удается. Если я найду что-то такое чистое (без других и других массивных методов), я отправлю ответ. – PedroSilva

+5

PedroSilva, это неверно. Вот пример: «Swift» .componentsSeparatedByString («Swift»). Count' печатает '2'. Таким образом, 'count-1' будет печатать количество вхождений, в этом случае' 1'. –

10

Я бы рекомендовал расширение для строки в Swift 3, например:

extension String { 
    func countInstances(of stringToFind: String) -> Int { 
     var stringToSearch = self 
     var count = 0 
     while let foundRange = stringToSearch.range(of: stringToFind, options: .diacriticInsensitive) { 
      stringToSearch = stringToSearch.replacingCharacters(in: foundRange, with: "") 
      count += 1 
     } 
     return count 
    } 
} 

Это петля, которая находит и удаляет каждый экземпляр stringToFind, увеличивая счетчик на каждом раунде. Как только searchString больше не содержит stringToFind, цикл прерывается, и счет возвращается.

Обратите внимание, что я использую .diacriticInsensitive, поэтому игнорирует акценты (например, резюме и резюме будут найдены). Вы можете добавить или изменить параметры в зависимости от типов строк, которые вы хотите найти.

+1

'replaceSubrange' может быть лучше, чем' replaceingCharacters', чтобы каждый раз создавать новую строку. Кроме того, использование 'range (of: options: range:)' может быть лучше, чем 'range (of: options:)', чтобы избежать поиска из startIndex каждый раз. –

+0

Я применил описанные оптимизации в [моем ответе] (https://stackoverflow.com/a/45073012/1033581). –

2

Мне нужен способ подсчета подстрок, который может содержать начало следующей подстроки. Использование dwsolbergs расширение и диапазон строк (из: вариантов: диапазон: локаль :) метод, который я придумал эту строку расширения

extension String 
{ 
    /** 
    Counts the occurrences of a given substring by calling Strings `range(of:options:range:locale:)` method multiple times. 

    - Parameter substring : The string to search for, optional for convenience 

    - Parameter allowOverlap : Bool flag indicating whether the matched substrings may overlap. Count of "" in "" is 2 if allowOverlap is **false**, and 3 if it is **true** 

    - Parameter options : String compare-options to use while counting 

    - Parameter range : An optional range to limit the search, default is **nil**, meaning search whole string 

    - Parameter locale : Locale to use while counting 

    - Returns : The number of occurrences of the substring in this String 
    */ 
    public func count(
     occurrencesOf substring: String?, 
     allowOverlap: Bool = false, 
     options: String.CompareOptions = [], 
     range searchRange: Range<String.Index>? = nil, 
     locale: Locale? = nil) -> Int 
    { 
     guard let substring = substring, !substring.isEmpty else { return 0 } 

     var count = 0 

     let searchRange = searchRange ?? startIndex..<endIndex 

     var searchStartIndex = searchRange.lowerBound 
     let searchEndIndex = searchRange.upperBound 

     while let rangeFound = range(of: substring, options: options, range: searchStartIndex..<searchEndIndex, locale: locale) 
     { 
      count += 1 

      if allowOverlap 
      { 
       searchStartIndex = index(rangeFound.lowerBound, offsetBy: 1) 
      } 
      else 
      { 
       searchStartIndex = rangeFound.upperBound 
      } 
     } 

     return count 
    } 
} 
6

Оптимизация dwsolbergs solution рассчитывать быстрее. Также быстрее, чем componentsSeparatedByString.

extension String { 
    func countInstances(of stringToFind: String) -> Int { 
     assert(!stringToFind.isEmpty) 
     var searchRange: Range<String.Index>? 
     var count = 0 
     while let foundRange = range(of: stringToFind, options: .diacriticInsensitive, range: searchRange) { 
      searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex)) 
      count += 1 
     } 
     return count 
    } 
} 

Использование:

// return 2 
"aaaa".countInstances(of: "aa") 
+1

Очень приятное решение, тем более, что, изменив параметры на '[.caseInsensitive,.diacriticInsensitive] 'он может найти поисковый запрос без учета верхнего/нижнего регистра. Браво! – ConfusionTowers

0

Попробуйте

var mainString = "hello Swift Swift and Swift" 
var count = 0 

mainString.enumerateSubstrings(in: mainString.startIndex..<mainString.endIndex, options: .byWords) { (subString, subStringRange, enclosingRange, stop) in 

    if case let s? = subString{ 

     if s.caseInsensitiveCompare("swift") == .orderedSame{ 
      count += 1 
     } 
    } 


} 

print(count) 
Смежные вопросы