Swift中字符串中子字符串的出现次数

时间:2015-07-31 12:28:01

标签: regex swift

我的主要字符串是“hello Swift Swift and Swift”,substring是Swift。 我需要获得在提到的字符串中出现子串“Swift”的次数。

此代码可以确定模式是否存在。

var string = "hello Swift Swift and Swift"

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

现在我需要知道发生的次数。

11 个答案:

答案 0 :(得分:77)

一种简单的方法是在"Swift"上拆分,并从零件数量中减去1:

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

此代码打印3。

修改Swift 3 syntax之前代码如下:

let tok =  s.componentsSeparatedByString("Swift")

答案 1 :(得分:15)

我建议在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,因此它会忽略重音(例如,可以找到résume和resume)。您可能希望根据要查找的字符串类型添加或更改选项。

答案 2 :(得分:13)

优化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建议。

答案 3 :(得分:9)

您是否想要计算字符而不是子字符串:

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

答案 4 :(得分:3)

我需要一种方法来计算可能包含下一个匹配子字符串的开头的子字符串。利用dwsolbergs扩展和字符串范围(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
    }
}

答案 5 :(得分:2)

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

答案 6 :(得分:1)

为什么不仅仅使用一些长度数学?

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

答案 7 :(得分: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)

答案 8 :(得分:0)

我的解决方案可能是使用String.Index而不是Int范围会更好,但我认为这样更容易阅读。

extension String {
    func count(of char: Character, range: (Int, Int)? = nil) -> Int {
        let range = range ?? (0, self.count)

        return self.enumerated().reduce(0) {
            guard ($1.0 >= range.0) && ($1.0 < range.1) else { return $0 }
            return ($1.1 == char) ? $0 + 1 : $0
        }
    }
}

答案 9 :(得分:0)

使用高阶函数的解决方案

func subStringCount(str: String, substr: String) -> Int {
    { $0.isEmpty ? 0 : $0.count - 1 } ( str.components(separatedBy: substr))
}

单元测试

import XCTest

    class HigherOrderFunctions: XCTestCase {

        func testSubstringWhichIsPresentInString() {
            XCTAssertEqual(subStringCount(str: "hello Swift Swift and Swift", substr: "Swift"), 3)
        }

        func testSubstringWhichIsNotPresentInString() {
            XCTAssertEqual(subStringCount(str: "hello", substr: "Swift"), 0)
        }

    }

答案 10 :(得分:0)

出于完整性的考虑–并且因为有一个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是可选的。