【问题标题】:How to find Number of Occurences of Slash from a strings如何从字符串中查找斜线的出现次数
【发布时间】:2012-02-13 13:02:44
【问题描述】:

如何使用 Excel VBA 宏查找字符串中正斜杠字符 ( / ) 的出现次数?

【问题讨论】:

    标签: excel vba


    【解决方案1】:

    老问题,但我想我会通过我在 excel 论坛上找到的答案来增加答案的质量。显然计数也可以使用。

        count =Len(string)-Len(Replace(string,"/",""))
    

    答案的全部归功于原作者:http://www.ozgrid.com/forum/showthread.php?t=45651

    【讨论】:

    • 哈!刚想到那个,不过特地来这里看看有没有更好的解决办法。
    • 它的美妙之处在于,您可以在公式中轻松使用它,无需 VBA,使用 SUBSTITUTE()
    • 一个更通用的答案是count = (Len(string)-Len(Replace(string,"/",""))) / len("/")。那么你也可以统计长度大于1的字符串。
    【解决方案2】:
    Function CountOfChar(str as string, character as string) as integer
          CountOfChar = UBound(Split(str, character))
    End Function
    

    【讨论】:

    • 这是最好的。您也可以查找分组的字符集。
    • @Vityata 我不关注。这个ubound(split("x x "," ")) 返回 4,这就是你想要的(字符串是 x[space][space][space]x[space])。你能提供一个可行的例子来说明它是如何不起作用的吗?
    • @mountainclimber - 实际上它有效,对不起,我在想别的东西 - 在Replace() 中,空间合二为一。
    • 你少了一行代码:如果是str = "",结果是-1。另外我将参数命名为inThiscountThis,因为第二个不限于字符,它也可以用作更长的字符串。
    • 我同意@miroxlav 的说法,即命名约定有点偏离,但这是迄今为止最好的答案。而且我认为没有任何遗漏,您也可以在代码中使用-1 结果(即if result = -1 then...)。显然,如果您不关心-1,那么您可以添加“缺失行”,但这是一个偏好问题。
    【解决方案3】:

    使用下面的函数,如count = CountChrInString(yourString, "/")

    '''
    ''' Returns the count of the specified character in the specified string.
    '''
    Public Function CountChrInString(Expression As String, Character As String) As Long
    '
    ' ? CountChrInString("a/b/c", "/")
    '  2
    ' ? CountChrInString("a/b/c", "\")
    '  0
    ' ? CountChrInString("//////", "/")
    '  6
    ' ? CountChrInString(" a / b / c ", "/")
    '  2
    ' ? CountChrInString("a/b/c", " / ")
    '  0
    '
        Dim iResult As Long
        Dim sParts() As String
    
        sParts = Split(Expression, Character)
    
        iResult = UBound(sParts, 1)
    
        If (iResult = -1) Then
        iResult = 0
        End If
    
        CountChrInString = iResult
    
    End Function
    

    【讨论】:

    • 不是匈牙利符号的忠实粉丝,但感谢添加 cmets :-)
    • 有两种不同的匈牙利符号。这实际上是 Systems Hungarian,最占主导地位,并且不是最初也被称为 Apps Hungarian 的原始概念。它们之间有很大的不同,你可以在这里阅读:joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong
    【解决方案4】:

    当您不想调用单独的函数时,可以使用单行版本。它只是 CountChrInString 和上面其他一些的压缩版本。

    ? UBound(Split("abcabcabc", "cd"), 1)
    

    这将返回 0。如果将“cd”更改为“ab”,则返回 3。它也适用于变量。请注意,如果正在检查的字符串 (abcabc...) 为空,它将返回 -1。

    【讨论】:

      【解决方案5】:

      顺便说一句,如果您关注性能,以下比使用拆分或替换来确定计数快 20%:

      Private Function GetCountOfChar( _
        ByRef ar_sText As String, _
        ByVal a_sChar As String _
      ) As Integer
        Dim l_iIndex As Integer
        Dim l_iMax As Integer
        Dim l_iLen As Integer
      
        GetCountOfChar = 0
        l_iMax = Len(ar_sText)
        l_iLen = Len(a_sChar)
        For l_iIndex = 1 To l_iMax
          If (Mid(ar_sText, l_iIndex, l_iLen) = a_sChar) Then 'found occurrence
            GetCountOfChar = GetCountOfChar + 1
            If (l_iLen > 1) Then l_iIndex = l_iIndex + (l_iLen - 1) 'if matching more than 1 char, need to move more than one char ahead to continue searching
          End If
        Next l_iIndex
      End Function
      

      【讨论】:

        【解决方案6】:

        我喜欢 Santhosh Divakar 的回答,因此我对其进行了扩展,以解决当您希望通过将结果除以搜索字符的长度来检查多个字符时的可能性,如下所示:

        Function Num_Characters_In_String(Input_String As String, Search_Character As String) As Integer
        'Returns the number of times a specified character appears in an input string by replacing them with an empty string
        '   and comparing the two string lengths. The final result is then divided by the length of the Search_Character to
        '   provide for multiple Search Characters.
        
            Num_Characters_In_String = (Len(Input_String) - Len(Replace(Input_String, Search_Character, ""))) / Len(Search_Character)
        
        End Function
        

        例如,

        的结果
        Num_Characters_In_String("One/Two/Three/Four//", "//")
        

        给你 1,因为句尾只有一个双斜线。

        【讨论】:

          【解决方案7】:

          如果您关注性能和最小内存使用,拆分和 Len/Replace 解决方案都不是最佳的。

          这是我的建议

          Public Function CountOf(ByRef s As String, ByRef substr As String, Optional ByVal compareMethod As VbCompareMethod = vbBinaryCompare) As Integer
          
          Dim c As Integer
          Dim idx As Integer
          
          NEXT_MATCH:
          idx = InStr(idx + 1, s, substr, compareMethod)
          If idx > 0 Then
              c = c + 1
              GoTo NEXT_MATCH:
          End If
          
          CountOf = c + 1
          End Function
          

          这是性能,在一个简单的案例和一个包含更多条目的案例上运行每个选项 1,000,000 次:

          5.828ms       Empty Loop
          s = '0,1,2,3,4,5,6,7,8,9', separator = ','
          1.882s         UBound(Split) algo
          2.537s         Len/Replace() algo
          760.710ms      CountOf()
          
          s = '[ABC],long, longer,sdfgshttsdbghhgsssssshsdhhhhhhhhhhhh,,,,777777777777777777777777777777,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,LAST', separator = ','
          18.330s        UBound(Split) algo
          21.743s        Len/Replace() algo
          9.544s         CountOf()
          

          因此,即使 CountOf 是一个函数调用,而 Split 和 Len/Replace 直接在循环代码中,总体速度也快了大约 2 到 3 倍。

          还要注意,当项目数量和长度增加时,性能比保持稳定,如下所示(仅用 1000 次迭代完成测试)

          s ="[ABC],long,longer,sdfgshttsdbghhgsssssshsdhhhhhhhhhhhh,,,,777777777777777777777,Repeat(1000,"A...Z"),LAST', separator = ','
          232.160ms      UBound(Split): 1033
          325.367ms      Len/Replace(): 1033
          113.658ms      CountOf(): 1033
          

          【讨论】:

          • 是的,但在大多数情况下,只完成了几个计数。因此,差异将是一些 µS。更重要的是,你不会因为使用 GoTo 代替正常循环而从你的代码朋友那里得到很多功劳。
          【解决方案8】:

          另一个不错的选择是使用 RegExp。我在 Microsoft Word 中尝试了以下操作,但我确信它在 Excel 中的工作原理大致相同。

          在一个包含 190,000 个单词和 2,400 个三字母单词实例的 Word 文档中,以下函数平均需要 0.938 秒来计算它们(我在其下方添加了一个 Sub 以方便显示时间):

          Function RegExpCount(WholeString As String, Substring As String) As Long
          
          Dim MatchCol As MatchCollection
          
          With New RegExp
              .Pattern = Substring
              .Global = True
              .IgnoreCase = False 'or True, depending on your needs
              .MultiLine = False
              Set MatchCol = .Execute(WholeString)
          End With
          
          RegExpCount = MatchCol.count
          
          End Function
          
          Sub CountInstances()
          Dim StartTime As Double
          Dim SecondsElapsed As Double
          'Remember time when macro starts
            StartTime = Timer
          
          Dim Rng As Range
          Set Rng = ActiveDocument.Range
          Debug.Print "The number of times 'your substring' appears in this document is: " & RegExpCount(Rng.Text, "your substring")
          
          'Calculate how many seconds code took to run
            SecondsElapsed = Round(Timer - StartTime, 2)
          
          'Notify user in seconds
            MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
          
          End Sub
          

          它总是正确输出 2,400。 Alexis Martial 的 CountOf 函数和 Rick_R 的 UBound(Split) 命令所用的时间相同。它们都在大约 0.92-0.95 秒内输出相同的计数。

          【讨论】:

          • 小心这个,它不会像你说的那样做!此解决方案将返回您作为Substring 传入的正则表达式模式的匹配数。例如,将 "\w+" 传递为 Substring 不会计算 "\w+" 的出现次数,而是计算 WholeString 中的单词数。这当然是一个更强大的功能,但并不是你说的那样。要实际计算出现次数,您必须首先转义 Substring 中的所有正则表达式“特殊字符”。它们是:.+*?^$())[{、@98654336@、{ , |, \.
          • 转义正则表达式“特殊字符”可以通过在其前面放置 \ 来完成。因此,您首先必须使用如下表达式编辑您的 SubstringSubstring = replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(Substring, "\", "\\") ".", "\."), "+", "\+"), "*", "\*"), "?", "\?"), "^", "\^"), "$", "\$"), "(", "\("), ")", "\)"), "[", "\["), "]", "\]"), "{", "\{"), "}", "\}"), "|", "\|") 以使代码执行您所说的操作,即计算 WholeStringSubstring 的出现次数。
          • 是的,我知道。我想我在遇到正则表达式元字符时习惯于转义它们,但每个用户都不会意识到这一点。与其说三遍函数没有按照我所说的那样做,不如说它按照我所说的那样做会更准确,只是你必须转义 14 个 RegExp 元字符。
          • 顺便说一句,我从来没有想过像这样嵌套替换命令和字符串。这很整洁。
          • 说它不做你说它做的事情是完全准确的。我绝不是要批评你个人,这只是对那些可能会使用你的代码的人的警告,因为来自 Stackoverflow 的代码被大量复制,人们必须意识到这一点......我就像您将 Regex 方法的性能与其他方法进行比较一样,它会向该线程添加信息!关于嵌套替换,是的,它并没有真正成为最易读的代码,但在评论中,这是我看到的唯一选择:)
          【解决方案9】:

          这是 VBA Excel 宏的简单解决方案。

          Function CharCount(str As String, chr As String) As Integer
               CharCount = Len(str) - Len(Replace(str, chr, ""))
          End Function
          

          【讨论】:

          • 您的回答与 Santhosh Divakar 的回答有何不同?
          【解决方案10】:

          如上所述,性能和内存利用率不太可能成为问题,但在将大文件读入单个字符串的情况下,它可能会成为问题。 @Alexis_Martial 尝试了这个,但是 a) 使用了不必要的 goto 语句 b) 没有考虑到正在搜索的字符串的长度。

          Public Function Occurences(ByRef s As String, ByRef substr As String, Optional ByVal compareMethod As VbCompareMethod = vbBinaryCompare) As Long
          Dim idx As Long
          Dim sublen As Long
              sublen = Len(substr)
              idx = 1
              Occurences = -1
              Do
                  Occurences = Occurences + 1
                  idx = InStr(idx, s, substr, compareMethod) + sublen
              Loop While idx > sublen
          End Function
          

          【讨论】:

            猜你喜欢
            • 2012-12-26
            • 2012-02-14
            • 2023-03-13
            • 2021-03-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多