web-dev-qa-db-fra.com

Nombre d'occurrences de sous-chaîne dans une chaîne dans Swift

Ma chaîne principale est "hello Swift Swift and Swift" et la sous-chaîne est Swift . Je dois connaître le nombre de fois que la sous-chaîne "Swift" apparaît dans la chaîne mentionnée.

Ce code peut déterminer si le motif existe.

var string = "hello Swift Swift and Swift"

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

Maintenant, j'ai besoin de connaître le nombre d'occurrences.

29
Reza

Une approche simple consisterait à scinder le "Swift" et à soustraire 1 du nombre de parties:

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

Ce code imprime 3.

Edit: Before Syntaxe de Swift 3 le code ressemblait à ceci:

let tok =  s.componentsSeparatedByString("Swift")
71
dasblinkenlight

Je recommanderais une extension de chaîne dans Swift 3 telle que:

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

C'est une boucle qui trouve et supprime chaque instance de la chaîne stringToFind, en incrémentant le compte à chaque remise. Une fois que la chaîne searchString ne contient plus de chaîneToFind, la boucle est interrompue et le décompte est renvoyé.

Notez que j'utilise .diacriticInsensitive afin qu'il ignore les accents (par exemple, CV et CV seraient tous deux trouvés). Vous voudrez peut-être ajouter ou modifier les options en fonction du type de chaîne que vous souhaitez rechercher.

14
dwsolberg

Optimisation solution de dwsolbergs pour compter plus rapidement. Aussi plus rapide que componentsSeparatedByString.

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

Usage:

// return 2
"aaaa".countInstances(of: "aa")
  • Si vous voulez ignorer les accents, vous pouvez remplacer options: [] par options: .diacriticInsensitive comme l'a fait dwsolbergs.
  • Si vous voulez ignorer la casse, vous pouvez remplacer options: [] par options: .caseInsensitive comme suggéré par ConfusionTowers.
  • Si vous souhaitez ignorer les accents et les majuscules, vous pouvez remplacer options: [] par options: [.caseInsensitive, .diacriticInsensitive] comme suggéré par ConfusionTowers.
11
Cœur

Si vous souhaitez compter les caractères plutôt que les sous-chaînes:

extension String {
    func count(of needle: Character) -> Int {
        return reduce(0) {
            $1 == needle ? $0 + 1 : $0
        }
    }
}
7
mxcl

J'avais besoin d'un moyen de compter les sous-chaînes pouvant contenir le début de la prochaine sous-chaîne correspondante. Utilisation de dwsolbergs extension et de la chaîne Strings (of: options: range: locale :) method

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
    }
}
3
Christian Otkjær

Essaye ça

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)