我的主字符串是"hello Swift Swift and Swift",子字符串是Swift。 我需要获取在提到的字符串中子字符串"Swift"出现的次数。
这段代码可以确定模式是否存在。
var string = "hello Swift Swift and Swift"
if string.rangeOfString("Swift") != nil {
println("exists")
}
现在我需要知道出现的次数。
"Swift"
进行分割,然后从部分数量中减去1:let s = "hello Swift Swift and Swift"
let tok = s.components(separatedBy:"Swift")
print(tok.count-1)
这段代码打印出3。
编辑:在Swift 3语法之前,代码看起来像这样:
let tok = s.componentsSeparatedByString("Swift")
如果您想要计算字符而不是子字符串:
extension String {
func count(of needle: Character) -> Int {
return reduce(0) {
$1 == needle ? $0 + 1 : $0
}
}
}
Swift 5 扩展
extension String {
func numberOfOccurrencesOf(string: String) -> Int {
return self.components(separatedBy:string).count - 1
}
}
使用示例
let string = "hello Swift Swift and Swift"
let numberOfOccurrences = string.numberOfOccurrencesOf(string: "Swift")
// numberOfOccurrences = 3
优化 dwsolbergs solution 以更快地进行计数,也比 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
}
}
使用方法:
// return 2
"aaaa".countInstances(of: "aa")
options: []
替换为options: .diacriticInsensitive
,就像dwsolbergs所做的那样。options: []
替换为options: .caseInsensitive
,就像ConfusionTowers建议的那样。options: []
替换为options: [.caseInsensitive, .diacriticInsensitive]
,就像ConfusionTowers所建议的那样。.literal
,它只会执行精确匹配。[.caseInsensitive, .diacriticInsensitive]
,它可以找到搜索词而不考虑大小写。太棒了! - ConfusionTowers我建议在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
}
}
这是一个循环,它会查找并删除每个字符串实例,并在每次循环中递增计数。一旦搜索字符串不再包含任何待查找的字符串,循环就会终止并返回计数。
请注意,我使用.diactricInsensitive以忽略重音(例如résume和resume都可以被找到)。您可能需要根据要查找的字符串类型添加或更改选项。
replaceSubrange
可能比 replacingCharacters
更好,以避免每次创建新字符串。此外,使用 range(of:options:range:)
可能比 range(of:options:)
更好,以避免每次从 startIndex 开始搜索。 - Cœur我需要一种方法来计算可能包含下一个匹配子字符串开头的子字符串的数量。利用dwsolbergs的扩展和Strings range(of:options:range:locale:)方法,我想出了这个String扩展。
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
}
}
extension String {
func occurences(of search:String) -> Int {
guard search.count > 0 else {
preconditionFailure()
}
let shrunk = self.replacingOccurrences(of: search, with: "")
return (self.count - shrunk.count)/search.count
}
}
试试这个
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)
import RegexBuilder
let text = "hello Swift Swift and Swift"
let match = text.matches(of: Regex{"Swift"})
print(match.count) // prints 3
将其用作函数
func countSubstrings(string : String, subString : String)-> Int{
return string.matches(of: Regex{subString}).count
}
print(countSubstrings(string: text, subString: "Swift")) //prints 3
将其用作扩展
extension String {
func countSubstrings(subString : String)-> Int{
return self.matches(of: Regex{subString}).count
}
}
print(text.countSubstrings(subString: "Swift")) // prints 3
为了完整性和因为有一个regex
标签,这是一个使用正则表达式的解决方案。
let string = "hello Swift Swift and Swift"
let regex = try! NSRegularExpression(pattern: "swift", options: .caseInsensitive)
let numberOfOccurrences = regex.numberOfMatches(in: string, range: NSRange(string.startIndex..., in: string))
.caseInsensitive
是可选的。