要做到这一点有许多不同的方法,但我们要为您介绍一种非常强大而且灵活的方法可以将文本文件当作数据库来处理(这基本上是您想要达成的目标)。实际上,您可以使用 ADO(ActiveX 数据对象)对文本文件运行数据库查询,尽管这并不广为人知。这正是我们用以下脚本执行的操作:
乍一看,您也许会对此查询困惑不解。您大概记得,我们的文本文件只包括一个字段:文件的每行中有一个城市名称,别无其他。但是,尽管我们的“数据库”只有一个字段,SQL 查询却指定了两个单独的项:City 和 Count(City) AS CountOfCity。这是怎么回事?
实际上,我们并未选择两个不同的字段;而只选择了一个字段 (City) 和一个用于计算每个城市在数据库中出现次数的“计算字段”。(计算字段是基于其他字段的数据计算得出的字段;该字段本身并不实际存在于数据库中。)我们可以将 Count(City) AS CountOfCity 项(与 GROUP BY City 子句联用)解读为:计算每个城市在文件中出现的次数,然后将该数字存储在名为 CountOfCity 的计算字段中。
可喜的是,我们检索到的记录集含有计算出的城市总数。另一种方法是,打开文本文件,读取每一行,然后使用数组或 Dictionary 对象记录每个城市名在文件中出现的次数。但 ADO 极大简化了这一过程。
您可能也注意到了这一点:我们没有从数据库表中选择(因为我们既没有数据库也没有表),而是在 SQL 查询中指定文本文件的名称。于是,我们从变量 strFile 选择数据,而此变量刚好代表我们文本文件的名称 (City_Names.txt)。
您好,SA。如果您是脚本编写方面的新手(或者您从未使用过 Split 函数),那我们就先从一个简要教程开始。正如 SA 所说,通过 Split 函数,可获得一个项或多个项(各项间以逗号等通用分隔符分隔)的文本字符串,然后创建一个包含各项的数组。例如,假设有以下文本行:
Dopey,Sneezy,Doc,Grumpy,Sleepy,Happy,Bashful
通过运行 Split 函数并告诉该函数逗号是分隔符(即分隔各项的字符),我们可以很容易地将此字符串分成以下组成部分:
Dopey
Sneezy
Doc
Grumpy
Sleepy
Happy
Bashful
总之,这是一个非常实用而小巧的函数,尤其是用于文件路径、Active Directory AdsPaths 及其他组成部分与整体同样重要的情况。(例如,Split 函数可将 C:\Scripts\MyScript.vbs 这样的文件路径拆分成驱动器、文件夹和文件名。)
这的确不错。但是 SA 想知道一个文本字符串可分为多少项;例如,我们不想知道“七个小矮人”的名字,只想知道该字符串中列出了七个小矮人。
注意。尽管有自吹自擂之嫌,但我们仍要指出,脚本专家(常被误认为是“七个小矮人”)不需查证就知道所有这七个名字。还有一点要对那些对琐事津津乐道者说明的是:Dopey(常常与脚本专家混淆的小矮人)最初叫 Deafy。很奇怪,但却千真万确! |
那么,如何确定字符串中找到的项数呢?我们只需使用下面这一小段简单的脚本:
strNames = "Dopey,Sneezy,Doc,Grumpy,Sleepy,Happy,Bashful"
arrNames = Split(strNames, ",")
Wscript.Echo Ubound(arrNames) + 1
在第 1 行,我们将七个小矮人的名字(名字间用逗号分隔)分配给一个名为 strNames 的变量。在第 2 行,我们调用 Split 函数,并指示分隔符是逗号。因此,您会看到“,”是传递给 Split 的第二个参数;第一个参数当然要对其执行 Split 的字符串。此操作会返回一个名为 arrNames 的数组,数组中的每项代表一个小矮人的名字。(顺便说一下,名称 arrNames 完全是随意指定的;您可以使用想要的任何变量名。)
接下来是第 3 行:
Wscript.Echo Ubound(arrNames) + 1
在此我们要执行的操作是回显数组的 Ubound(上限)值,并加上 1。其用意如何呢?是这样的,在数组中,每项会自动分配有一个索引号:分配给第一项的索引号是 0,分配给第二项的是 1,以此类推。在内存中,数组类似如下:
索引号 |
项 |
0 |
Dopey |
1 |
Sneezy |
2 |
Doc |
3 |
Grumpy |
4 |
Sleepy |
5 |
Happy |
6 |
Bashful |
Ubound 函数将始终返回数组中最后一项的索引号;在此例中,Ubound 返回 6。Ubound 值始终比数组中的项数少一;请记住,此数组中实际有七项。之所以会这样,是因为分配给数组中第一项的索引号是 0;如果第一项的索引号是 1,则 Ubound 值也会代表数组中的总项数。但是没关系:我们只需取 Ubound 值,然后将其加 1,即可得出总项数。大功告成!
哦,还有一件事:是的,我们将极力阻止 Peter 在他的下次网络广播中演唱 Someday My Prince Will Come 的脚本编写相关版。我们说到做到。
如何去除字符串中的多余空格?
问:
我知道可以使用 Split 命令将类似如下句子:VBScript is fun!分离为单个单词的数组。但是,如果我有类似如下的句子该怎么办呢:VBScript is fun!我不能使用空格作为分隔符,因为可能有很多空格。并且,我也不能使用特定数目的空格作为分隔符,因为空格的数目有可能不同。请问你们有什么建议?
-- SC
答:
嗨,SC。您可能很难相信,但我们这些 Scripting Guy 也是有标准的,至少对这个专栏来说是这样。我们每天都会收到很多问题,我们并不能对这些问题一一回答。那么,我们如何决定发表哪些问题呢?首先,我们会找一些看来比较容易回答的问题。以下是一个提示:如果您的问题包含很多并且——“并且我希望脚本能够这样,并且我希望脚本能够那样,并且……”——好吧,那这个问题出现在成堆问题的顶部的机会就可能比较小。我们知道这有点不公平,但无论如何,这个专栏只是我们日常工作的一小部分。因此我们不能在任何一个问题上花费太多时间。
我们寻求的另外一件事情会更有吸引力:我们的多数受众是否会对这个问题的回答感兴趣或是使用它。再说一次,这并不总是那么公平,但是“主流”技术的问题通常会比深奥技术的问题更受欢迎。非常抱歉。
老实说,尽管我们并不确定您的脚本属于哪一类,但我们决定回答这个问题,因为我们发现这个问题很有意思。毕竟,怎么能去除这些多于的空格,从而将 VBScript is fun! 变成 VBScript is fun! 呢? 以下就是我们提供的解决方案:
问题不在于字符串中有空格;如果是那样的话,我们就可以使用 VBScript 的 Replace 函数来去除所有空格了。但是,我们希望在字符串中留有一些空格;事实上,我们希望使每两个单词之间具有一个空格。我们只是要去除多余的空格。最后,我们决定使用 Replace 函数,将所有具有多个空格的实例替换为一个空格。因此,如果我们找到 7 个连续的空格,我们会将这些空格替换为一个空格。
非常简单,除了一个问题以外。Replace 函数需要有一个可供搜索的字符串,您不能这样告诉它:“好吧,请搜索具有多个空格的实例,并将它们替换为一个空格。”相反,您需要使用类似如下的代码,这段代码可将 7 替换为一个空格:
strStarter = Replace(strStarter, “ “, " ")
太好了,除了还不知道需要搜索几个空格以外;既然字符串中可能含有 7 个连续空格,那么其中也有可能含有 5 个连续空格。这怎么办呢?
我们使用以下脚本来处理这种情况。以下代码我们会在稍候解释:
strStarter = "VBScript is fun!"
intStarter = Len(strStarter)
For i = intStarter to 2 Step -1
strChars = Space(i)
strStarter = Replace(strStarter, strChars, " ")
Next
arrStarter = Split(strStarter, " ")
For Each strUnit in arrStarter
Wscript.Echo strUnit
Next
我们最后所做的就是说:“好吧,我们需要搜索由几个空格组成的字符串,但我们不知道每个字符串中可能包含几个空格。”这是有一点麻烦,直到我们发现,比如说吧,这个字符串总共有 37 个字符。这就是说字符串中最多可能有 37 个连续空格(假定这个字符串完全由空格组成)。因此,我们可以从搜索 37 个连续空格开始,如果找到了,那么我们就将它们替换为一个空格。然后,我们搜索 36 个连续空格,然后是 35 个,再然后是 34 个。我们一直这么搜索,直到最后搜索 2 个空格,并将这些空格都替换为一个空格。此时,我们就去除了所有多余的空格。
没什么新意,对吧?并且,令人惊奇的是,这种事情很容易做。注意在我们的脚本中,我们首先将某个字符串分配给变量 strStarter。然后我们使用以下代码来确定 strStarter 中有多少个字符:
intStarter = Len(strStarter)
我们还是假设其中有 37 个字符。我们需要做的就是从 37 开始一直循环到 2。猜一猜会发生什么呢?以下就是这个循环所做的:
For i = intStarter to 2 Step -1
strChars = Space(i)
strStarter = Replace(strStarter, strChars, " ")
Next
这个循环从字符串中的字符数开始执行,然后使用 Step -1 参数循环递减到 2。什么是 Step -1 呢?默认情况下,For Next 循环执行的时候每次递增 1。例如,以下循环从 1 开始执行,然后每次递增 1,直至循环到 10:
For i = 1 to 10
在我们的循环中,我们从最大数 (37) 开始,然后一直循环到 2,每次将 i 的值递减 1。明白了吧?这就是 Step -1 所做的;它实际上就是循环运行一次就减去 1。
在循环内部我们做两件事情。首先,我们需要创建一个由 i 个空格组成的字符串。幸好,我们可以使用一行代码做到这点,多亏有 Space 函数:
strChars = Space(i)
其次,我们需要检查 strStarter 是否可能存在由 i 个空格组成的子字符串。如果可能,则我们需要将它替换为一个空格。以下代码可实现这个目的:
strStarter = Replace(strStarter, strChars, " ")
从这里开始,我们继续执行循环,直到最后检查 2 个连续空格。然后我们退出循环,并使用 Split 命令将字符串划分为由单个单词组成的数组,然后——仅仅是为了证明上述过程有效——我们回显这些单词。
现在,这还不是十分保险;例如,如果您有一些多余的空格位于单词 VBScript 的前面呢?我们不再赘述这种情况,不过您可以使用 VBScript 的 Trim 和 RTrim 函数来去除起始空格和尾部空格。如果您希望了解有关字符串操作的更多信息,请参阅以下地址的相关部分:《Microsoft Windows 2000 脚本编写指南》中的相关部分.
我们也不知道类似于 VBScript is fun! 这样的字符串可能出现的环境。我们猜想您可能在尝试读取固定长度的日志文件时遇到这样的字符串。如果是这样,上述代码会有效,但您可能会发现使用ADO (ActiveX Database Objects) 来分析该文件会更简单