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.
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")
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.
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: []
paroptions: .diacriticInsensitive
comme dwsolbergs l'a fait. - Si vous voulez ignorer la casse, vous pouvez remplacer
options: []
paroptions: .caseInsensitive
comme ConfusionTowers suggéré. - Si vous voulez ignorer les accents et la casse, vous pouvez remplacer
options: []
paroptions: [.caseInsensitive, .diacriticInsensitive]
comme ConfusionTowers suggéré.
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
}
}
}
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
}
}
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)