【发布时间】:2012-02-13 13:02:44
【问题描述】:
如何使用 Excel VBA 宏查找字符串中正斜杠字符 ( / ) 的出现次数?
【问题讨论】:
如何使用 Excel VBA 宏查找字符串中正斜杠字符 ( / ) 的出现次数?
【问题讨论】:
老问题,但我想我会通过我在 excel 论坛上找到的答案来增加答案的质量。显然计数也可以使用。
count =Len(string)-Len(Replace(string,"/",""))
答案的全部归功于原作者:http://www.ozgrid.com/forum/showthread.php?t=45651
【讨论】:
SUBSTITUTE()
count = (Len(string)-Len(Replace(string,"/",""))) / len("/")。那么你也可以统计长度大于1的字符串。
Function CountOfChar(str as string, character as string) as integer
CountOfChar = UBound(Split(str, character))
End Function
【讨论】:
ubound(split("x x "," ")) 返回 4,这就是你想要的(字符串是 x[space][space][space]x[space])。你能提供一个可行的例子来说明它是如何不起作用的吗?
Replace() 中,空间合二为一。
str = "",结果是-1。另外我将参数命名为inThis 和countThis,因为第二个不限于字符,它也可以用作更长的字符串。
-1 结果(即if result = -1 then...)。显然,如果您不关心-1,那么您可以添加“缺失行”,但这是一个偏好问题。
使用下面的函数,如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
【讨论】:
当您不想调用单独的函数时,可以使用单行版本。它只是 CountChrInString 和上面其他一些的压缩版本。
? UBound(Split("abcabcabc", "cd"), 1)
这将返回 0。如果将“cd”更改为“ab”,则返回 3。它也适用于变量。请注意,如果正在检查的字符串 (abcabc...) 为空,它将返回 -1。
【讨论】:
顺便说一句,如果您关注性能,以下比使用拆分或替换来确定计数快 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
【讨论】:
我喜欢 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,因为句尾只有一个双斜线。
【讨论】:
如果您关注性能和最小内存使用,拆分和 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
【讨论】:
另一个不错的选择是使用 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@、{ , |, \.
\ 来完成。因此,您首先必须使用如下表达式编辑您的 Substring:Substring = replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(Substring, "\", "\\") ".", "\."), "+", "\+"), "*", "\*"), "?", "\?"), "^", "\^"), "$", "\$"), "(", "\("), ")", "\)"), "[", "\["), "]", "\]"), "{", "\{"), "}", "\}"), "|", "\|") 以使代码执行您所说的操作,即计算 WholeString 中 Substring 的出现次数。
这是 VBA Excel 宏的简单解决方案。
Function CharCount(str As String, chr As String) As Integer
CharCount = Len(str) - Len(Replace(str, chr, ""))
End Function
【讨论】:
如上所述,性能和内存利用率不太可能成为问题,但在将大文件读入单个字符串的情况下,它可能会成为问题。 @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
【讨论】: