在文本文件中搜索字符串出现的次数

4

我想读取一个文本文件,并计算短语/字符串(而不是单词)在文本文件中出现的次数,但目前我的代码只有以下内容:

Const ForReading = 1

Set objFSO = CreateObject("Scripting.FileSystemObject")

Set objFile = objFSO.OpenTextFile("D:\VBscript project\testing.txt", ForReading)
strContents = objFile.ReadAll
objFile.Close

i = 0

arrLines = Split(strContents, "")

For Each strLine in arrLines
    If InStr(strLine, "hi there") Then
        i = i + 1
    End If
Next

WScript.Echo "Number of times word occurs: " & i

这只能让我计算单词出现次数,当我尝试调整它以计算短语时,它就不起作用了。

4个回答

5
考虑以下示例:
strPath = "D:\VBscript project\testing.txt"
strPhrase = "hi there"

strContent = ReadTextFile(strPath, 0)
arrContent = Split(strContent, strPhrase)

MsgBox "Number of times phrase occurs: " & UBound(arrContent)

Function ReadTextFile(strPath, lngFormat)
    ' lngFormat -2 - System default, -1 - Unicode, 0 - ASCII
    With CreateObject("Scripting.FileSystemObject").OpenTextFile(strPath, 1, False, lngFormat)
        ReadTextFile = ""
        If Not .AtEndOfStream Then ReadTextFile = .ReadAll
        .Close
    End With
End Function

请注意,基于 Split 的方法区分大小写。

4
strPath = "D:\VBscript project\testing.txt"
strPhrase = "hi there"

strContent = ReadTextFile(strPath, 0)
arrContent = Split(strContent, strPhrase)

MsgBox "Number of times phrase occurs: " & UBound(arrContent)

Function ReadTextFile(strPath, lngFormat)
    ' lngFormat -2 - System default, -1 - Unicode, 0 - ASCII
    With CreateObject("Scripting.FileSystemObject").OpenTextFile(strPath, 1, False, lngFormat)
        ReadTextFile = ""
        If Not .AtEndOfStream Then ReadTextFile = .ReadAll
        .Close
    End With
End Function

2
如果我的理解是正确的,而你所要求的确实像它看起来的那么简单,你只需要将“hi there”字符串更改为一个参数。这样你就可以动态地告诉你的函数要查找什么。
编辑:感谢@omegastripes,我注意到了之前代码中的一个缺陷,因此这是一个可以正常运行的代码。
代码应该像这样:
Sub yourSubName (pstrTextToCount)
    Const ForReading = 1
    Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
    Dim objFile : Set objFile = objFSO.OpenTextFile("D:\VBscript project\testing.txt", ForReading)
    Dim strContents : strContents = objFile.ReadAll
    objFile.Close

    ' You don't need these objects anymore, so release them
    Set objFile = Nothing
    Set objFSO = Nothing

    Dim intTextPosition : intTextPosition = 0
    Dim i : i = -1
    Do
      i = i + 1
      intTextPosition = InStr(intTextPosition + 1, strContents, pstrTextToCount)
    Loop While (intTextPosition > 0)

    Wscript.Echo "Number of times '" & pstrTextToCount & "' occurs: " & i
End Sub

我假设你的“Sub”只会执行这个操作,这就是为什么我把它放在“Sub”和“End Sub”语句中的原因。你可以添加任何其他代码,但请记住在“Sub”的签名中添加所需的参数才能使其工作。
PS:作为良好的实践,始终使用“Dim”声明变量,并使用“Set objName = Nothing”释放不再需要的对象的内存。

"Split(strContents, "")" 是无用的,因为它只返回一个元素。 - omegastripes
好的,如果一个字符串包含 pstrTextToCount 文本两次,它会正确地计算它们吗? - omegastripes
我只是提示不要将整个文本分成单独的行;) 并且切换到使用其他方法代替 InStr - omegastripes
1
正确到一定程度。你和@omegastripes的方法都只计算出现在单行上的短语。它们会跳过跨越多行的短语(例如,当两个单词之间有换行符时)。这种情况可以通过在搜索匹配项之前将所有空格替换为一个空格来处理。 - Ansgar Wiechers
2
@Ansgar Wiechers,我同意您的看法,但这也可能取决于OP的意图。如果他/她想要考虑单词数,即使在它们之间有换行符,那么替换空格是必需的,但如果他只想计算在同一行中出现的特定词序列,我认为两个答案都可以解决问题。 - Victor Moraes
显示剩余4条评论

1

这里有一个使用正则表达式的版本,因此您可以指定搜索是否需要区分大小写。为了测试目的,我使用脚本本身的内容作为输入。

Dim path, phrase, content
path    = Wscript.ScriptFullName
phrase  = "hi there\^$*+?{}.()|[]"
content = CreateObject("Scripting.FileSystemObject").OpenTextFile(path).ReadAll

Function NumberOfPhrasesInString(phrase, text, IgnoreCase)
  Dim regexpr, matches
  Set regexpr = New RegExp
  phrase = RegExEscape(phrase)
  With regexpr
    .Pattern = phrase
    .Global  = True
    .IgnoreCase = IgnoreCase
    Set matches = .Execute(text)
  End With
  NumberOfPhrasesInString = matches.count
End Function

Function RegExEscape(str)
  Dim special
  RegExEscape = str
  special = "\^$*+?{.()|[]"
  For i=1 To Len(special)
    RegExEscape = replace(RegExEscape, Mid(special, i, 1), "\" & Mid(special, i, 1))
  Next
End Function

Wscript.Echo "Number of times phrase occurs: " & NumberOfPhrasesInString(phrase, content, false)

作为奖励,由于我在这里也切换到了Ruby版本。
path    = __FILE__ # the path to this script for test purposes
phrase  = 'HI THERE \ ^ $ * + ? { . ( | ['
puts phrase
content = File.read path

def number_of_phrases_in_string(phrase, text, ignoreCase=false )
  escaped = Regexp.escape(phrase)
  text.scan(Regexp.new(escaped, ignoreCase)).count.to_s 
end

puts "Number of times phrase occurs: " + number_of_phrases_in_string(phrase, content, true)

或者在一行中

puts File.read(__FILE__).scan(Regexp.new(Regexp.escape(phrase), true)).count

最后一行的true定义了大小写敏感。

将行phrase = "hi there"替换为phrase = "C:\Windows\System32" - omegastripes
@omegastripes:这是一个简单的例子,特殊字符需要转义,在Ruby中可以使用.escape实现,如果要搜索Vbscript,应该不会有问题。 - peter
目前,在模式中出现 \ ^ $ * + ? { . ( | [ 字符将导致意外结果。我认为你应该修复这个错误或在你的答案中指出这个特定的功能。 - omegastripes
没问题,我编辑了所有三个版本以应对特殊字符。 这再次展示了 Ruby 的强大之处,它在保持代码简洁易读的同时保持了可读性。 - peter
在 VBS 版本中,将行“phrase = "hi there^$*+?{.()|[]"”替换为“phrase = 'C:\Windows\System32'”。顺带一提,你为什么要在替换中使用“\”前缀? - omegastripes
1
@omegastripes:我猜你用错了源,只需要一个转义字符就可以工作了,或者使用"C:\Windows\System32",谢谢。 - peter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接