Swift: nombre d'occurrences de la sous-chaîne dans la chaîne

Ma Chaîne principale est "hello Swift Swift et Swift" et la sous-chaîne est Swift. J'ai besoin d'obtenir le nombre de fois que la sous-chaîne "Swift" se produit dans la chaîne.

Ce code peut déterminer si le motif existe. var string = "bonjour Swift Swift et Swift"

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

Maintenant, je dois connaître le nombre d'occurrence.

26
demandé sur Reza 2015-07-31 15:28:01

6 réponses

Une Approche simple serait de diviser sur "Swift", et de 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: Avant Swift 3 syntaxe le code ressemble à ceci:

let tok =  s.componentsSeparatedByString("Swift")
64
répondu dasblinkenlight 2018-02-01 10:06:40

Je recommanderais une extension à string 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 stringToFind, en incrémentant le compte sur chaque go-round. Une fois que la chaîne de recherche ne contient plus de stringToFind, la boucle se brise et le nombre revient.

Notez que j'utilise .diacriticInsensitive donc il ignore les accents (par exemple cv et CV seraient tous deux trouvés). Vous pouvez ajouter ou modifier les options en fonction des types de chaînes vous voulez trouver.

14
répondu dwsolberg 2017-07-13 06:02:09

Optimisation de la solution 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
    }
}

Utilisation:

// return 2
"aaaa".countInstances(of: "aa")
  • Si vous voulez ignorer les accents, vous pouvez remplacer options: [] par options: .diacriticInsensitive comme dwsolbergs l'a fait.
  • Si vous voulez ignorer la casse, vous pouvez remplacer options: [] par options: .caseInsensitive comme ConfusionTowers suggéré.
  • Si vous voulez ignorer les accents et la casse, vous pouvez remplacer options: [] par options: [.caseInsensitive, .diacriticInsensitive] comme ConfusionTowers suggéré.
10
répondu Cœur 2018-07-24 04:32:39

Si vous voulez 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
        }
    }
}
6
répondu mxcl 2018-03-29 02:34:27

J'avais besoin d'un moyen de compter les sous-chaînes qui peuvent contenir le début de la sous-chaîne correspondante suivante. Tirant parti de dwsolbergs extension et chaîne de chaîne (de: options: gamme: locale:) méthode je suis venu avec cette extension de chaîne

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
    }
}
2
répondu Christian Otkjær 2017-05-23 12:10:32

Essayez ceci

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)
0
répondu Deepalakshmi Govindraj 2017-10-05 20:01:53