您好,LA。您要知道,这正是脚本专家超越自我的问题之一。(请注意,倒不是说超越脚本专家是特别难的事。)首先,我们是在某个星期五编写本专栏,而且我们始终是在星期五寻求简单的解决方法。其次,恰好几天前我们参与了有关字数统计的讨论,所以我们的脑海里已经存在了这个主题。此问题听起来很简单,而且我们已经开始在考虑字数统计的问题:将上述两点加到一起,您就看到了星期五的完美专栏。
就是说我们的确思考了这个问题。
当我们坐下来想出您的问题的答案时,就立刻出现了第一处小麻烦。毕竟,我们还可以借助其它一些方法解决此问题。例如,通过 Microsoft Word 很容易就可以计算字数,因此我们脑海中浮现的第一个想法就是:“使用 Microsoft Word 就行了。”但是这似乎有些小题大做,而且我们也不想暗示只有出去买个 Microsoft Office 软件才能统计文本文件中的字数。(即使 Office 团队会给我们佣金,我们也要重新考虑这个想法。)然后我们会想到:“您知道,使用常规表达式可能是理想的方案。”不过,只要一想到常规表达式就会令人感到头痛,所以我们也放弃了该想法。
然后,我们想出了这个简单而明确的解决方案:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("c:/scripts/test.txt", ForReading)
strText = objFile.ReadAll
objFile.Close
arrWords = Split(strText, " ")
Wscript.Echo Ubound(arrWords) + 1
确实简单而明确:我们只需要打开文本文件 C:/Scripts/Test.txt,然后将整个文本文件存储到一个名为 strText 的变量中。然后,使用 Split 函数按照空格拆分数组(因为考虑到只有在两个字之间才会有空格。)使用 Split 函数创建了一个名为 arrWords 的数组(在这样的数组中,每个元素都代表一个单独的字)之后,我们仅需回显数组的 Ubound(上限)值,并加上 1。(为何要加上 1 呢?因为数组的 Ubound 值始终为数组中的项数减 1。)
这在某种程度上是可行的。可结果是,我们使用的文本文件有时会产生额外的空格以对齐信息:
Name Date
Ken Myer 3/30/2006
Pilar Ackerman 3/31/2006
这就会带来一个问题:其中每一个额外空格都作为一个字计数。这样,我们最终得出的字数就要比实际字数稍多一些。
让我们从头开始:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("c:/scripts/test.txt", ForReading)
strText = objFile.ReadAll
objFile.Close
arrWords = Split(strText, " ")
For Each strWord in arrWords
If Len(strWord) > 0 Then
i = i + 1
End If
Next
Wscript.Echo i
正如您所见到的,这次我们没有回显 Ubound 值。而是设置了一个 For Each 循环,以遍历数组中的所有项目。在该循环中,我们使用 Len 函数来确定每个单项中的字符数。如果项目的长度为 0,则说明我们遇到了一个多余空格。在这种情况下,我们仅需跳过该项目即可(因为几乎没有字会包含 0 个字符)。如果长度大于 0,则我们以 1 为单位递增计数器变量的值:
i = i + 1
遍历整个数组后,我们再回显计数器变量值:
Wscript.Echo i
这次准确多了,但是字数值似乎还是有点儿高。在对此问题苦思了一两分钟后,我们发现了原因。假定我们的文本文件包括这个句子:
Two plus two = four
多数人会说这个句子中有 4 个字;但我们的脚本却坚持认为此句中有 5 个字:
Two
plus
two
=
four.
为什么说有 5 个字呢?因为该脚本将等号 (=) 也作为一个字计入在内。同样,我们在文档中还有其他“无关的”字符:例如,以下结构会自动作为 3 个字计数:
. . .
真是让人厌烦。
我们不喜欢这样计数,因此我们最后一次修改了该脚本,用一系列的 Replace 函数来替换像等号和包含空格的句点这样的字符:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("c:/scripts/test.txt", ForReading)
strText = objFile.ReadAll
strText = Replace(strText, ",", " ")
strText = Replace(strText, ".", " ")
strText = Replace(strText, "!", " ")
strText = Replace(strText, "?", " ")
strText = Replace(strText, ">", " ")
strText = Replace(strText, "<", " ")
strText = Replace(strText, "&", " ")
strText = Replace(strText, "*", " ")
strText = Replace(strText, "=", " ")
strText = Replace(strText, vbCrLf, " ")
objFile.Close
arrWords = Split(strText, " ")
For Each strWord in arrWords
If Len(strWord) > 0 Then
i = i + 1
End If
Next
Wscript.Echo i
我们更钟意这个脚本。与我们先前的脚本一样,我们首先定义一个名为 ForReading 的常量;此常量会告知 FileSystemObject 我们要读取该文本文件(而不是向该文件写入或添加数据)。接下来我们创建一个 FileSystemObject 实例并使用 OpenTextFile 方法打开文件 C:/Scripts/Test.txt。一旦调出并运行 FileSystemObject 后,我们就使用 ReadAll 方法将该文件的全部内容读取到名为 strText 的变量中:
strText = objFile.ReadAll
然后,我们执行一系列的 Replace 函数以替换变量 strText 中的字符。(请注意,我们不会处理实际文件其本身,而只是处理内存中存储的该文件的副本。)例如,本行代码会以空格替换 strText 中的所有逗号:
strText = Replace(strText, ",", " ")
即便有要替换的字符,也请您自己决定替换哪些字符。如果您确定将等号和加号 (+) 作为单个字计数,则根本不必进行任何替换。
等一下,还要检查一个问题:有一个您必须要执行的替换。假定我们有如下所示的文本文件:
A
B
C
D
E
在这个文本文件中有多少个字呢?我们也会说有 5 个字,但是该脚本却认为仅有 1 个字。为什么?好吧,我们指示该脚本在空格处拆分文本;然而,在本文件中却没有任何空格,只是在每行的结尾处有回车换行符而已。因此,在我们的数组中仅包含一项。哎。
那么,我们如何解决这个问题呢?实际上,这相当容易:我们只要用空格替换所有回车换行符 (vbCrLf) 就行了:
strText = Replace(strText, vbCrLf, " ")
只要我们在每个字符之间用空格分隔(而不是用回车换行符分隔),该脚本就会针对此示例文本文件正确返回字数 5。
好了,我们讲到哪了?哦,是的。关闭文件后,我们则调用 Split 函数以将 strText 拆分为一个数组。然后,我们使用前述的 For Each 循环来统计数组中的字数(由此来统计该文本文件中的字数),遇到多余的空格则跳过。然后,我们回显计数器变量的值就万事大吉了。
至少我们对这个结果很满意。该字数是否 100% 准确还带有一些主观性。例如,假定文本文件中包含以下行:
2+2=4
在此行中有 5 个字(2、+、2、= 和 4)吗?也许仅有 3 个字:2、2 和 4。也许仅有 1 个字:2+2=4。(Microsoft Word 将其视为一个单字。)对此,您必须自己决定。对我们而言,我们已决定下次会找一个“容易的”问题来回答,我们会直接越过该问题而去尝试解决其它一些问题!