Skip to content

3. VBScript 编程基础

在描述了 VBScript 脚本的可能执行环境之后,我们将讨论该语言本身。从这里开始,我们将假设以下条件:

  1. 脚本容器为 WSH
  2. 脚本位于扩展名为 .vbs 的文件中

在介绍一个概念时,我们通常按以下步骤进行:

  • 如有必要,先介绍该概念
  • 展示一个示例程序及其运行结果
  • 如有必要,对结果和程序进行说明

VBScript 容器在脚本文本中不区分大小写。因此,您可以使用 wscript.echo "hello"WSCRIPT.ECHO "hello" 两种写法。

下面介绍的程序会在屏幕上输出大量内容,因此我们将重新回顾 wscript 对象的输出方法。

3.1. 显示信息

我们已经使用过 wscript 对象的 echo 方法,但它还有其他用于向屏幕写入内容的方法,如下面的脚本所示:

程序
结果
1
2
3
4
二 三

请注意以下几点:

  • 单引号后面的任何文本都被视为脚本注释,不会被 WSH 解释(第 1 行)。
  • echo 方法会打印其参数并换行,writeLine 方法也是如此(第 2 行和第 6 行)
  • write 方法会打印其参数,但不会换行(第 3 行)
  • 行尾字符由两个 ASCII 字符 13 和 10 组成。因此,第 4 行由表达式 chr(13) & chr(10) 表示,其中 chr(i) 表示 ASCII 字符 i,& 是字符串连接运算符。因此,"chat" & "eau" 表示字符串 "chateau"。
  • 行结束字符可以通过常量 vbCRLF 更简单地表示(第 5 行)

3.2. 在 VBScript 脚本中编写指令

默认情况下,每行只写一条指令。但是,可以通过用字符 : 分隔来在一行中写多条指令,例如 inst1:inst2:inst3。如果一行太长,可以将其拆分为几部分。在这种情况下,指令的不同部分必须以两个字符 (空格)_ 结尾。让我们重温前面的例子,并以不同的方式重写这些指令:

程序
结果
1
2
3
4
one
二 三

3.3. 使用 msgBox 函数显示文本

虽然在本文档中,我们几乎完全使用 wscript 对象在屏幕上显示文本,但还有一种更高级的函数可用于在窗口中显示信息。这就是 msgbox 函数,它通常使用三个参数:

msgbox 消息, 图标+按钮, 标题

  • message 是要显示的消息文本
  • 图标+按钮(可选)实际上是一个数字,用于指定要在消息窗口中放置的图标类型和按钮。该数字通常是两个数字的和:第一个数字决定图标,第二个数字决定按钮
  • title 是要放置在消息窗口标题栏中的文本

用于指定显示窗口中图标和按钮的值如下:

常量
描述
vbOKOnly
   0
仅显示“确定”按钮。
vbOKCancel
   1
显示“确定”和“取消”按钮。
vbAbortRetryIgnore
   2
显示“中止”、“重试”和“忽略”按钮。
vbYesNoCancel
   3
显示“是”“否”和“取消”按钮。
vbYesNo
   4
显示“是”和“否”按钮。
vbRetryCancel
   5
显示“重试”和“取消”按钮。
vbCritical
16
显示“关键消息”图标。
vbQuestion
32
显示“警告请求”图标。
vbExclamation
48
显示“警告请求”图标。
vbInformation
64
显示“信息”消息图标。
vbDefaultButton1
   0
第一个按钮是默认按钮。
vbDefaultButton2
256
第二个按钮是默认按钮。
vbDefaultButton3
512
第三个按钮是默认按钮。
vbDefaultButton4
768
第四个按钮是默认按钮。
vbApplicationModal
   0
模态应用程序;用户必须先响应该消息,才能继续在当前应用程序中工作。
vbSystemModal
4096
系统模态;在用户对消息作出响应之前,所有应用程序都将暂停。

以下是一些示例:

程序
结果
    
     
     

在某些情况下,会显示一个既作为信息窗口又作为输入窗口的信息框。例如,当提出一个问题时,我们希望知道用户是点击了“是”按钮还是“否”按钮。msgBox 函数会返回一个结果,我们在之前的程序中并未使用该结果。该结果是一个整数,表示用户点击了哪个按钮来关闭显示窗口:

常量
所选按钮
vbOK
1
确定
vbCancel
2
取消
vbAbort
3
中止
vbRetry
4
重试
vbIgnore
5
忽略
vbYes
6
vbNo
7

以下程序演示了如何使用 msgBox 函数的返回值。程序将显示一个带有“是”、“否”和“取消”按钮的窗口,共显示四次。您的操作如下:

  1. 单击“是”
  2. 点击“是”
  3. 单击“取消”
  4. 不点击任何按钮直接关闭窗口。程序会显示,此操作等同于点击“取消”按钮。
程序
结果

3.4. VBScript 中可用的数据类型

VBScript 仅识别一种数据类型:变体(Variant)。变体的值可以是数字(4、10.2)、字符串("hello")、布尔值(true/false)、日期(#01/01/2002#)、对象的地址,或者将所有这些数据类型组合在一起并存放在称为数组的结构中。

让我们来分析以下程序及其结果:

程序
结果
4
i=4
10.2
r1=10.2
0.014
r2=0.014
c1=hello
2002年1月10日
d1=10/01/02
10/01/02
d2=10/01/02
-1
b1=True
0
b2=False
v=4
v=10.2
v=hello
v=10/01/02
v=True

注释:

  • 许多编程语言(如 C、C++、Pascal、Java、C# 等)要求在使用变量之前必须先对其进行声明。这种声明包括指定变量的名称及其可容纳的数据类型(整数、浮点数、字符串、日期、布尔值等)。声明变量可以实现以下功能:
    • 确定变量所需的内存空间,因为不同的数据类型需要不同的内存量
    • 验证程序的一致性。例如,如果 i 是整数而 c 是字符串,将 ic 相乘就没有意义。如果变量 i c 的类型已被程序员声明,负责在执行前分析代码的程序就能标记此类不一致。

与大多数单数据类型的脚本语言(Perl、Python、JavaScript 等)一样,VBScript 允许在不进行声明的情况下使用变量。上文中的示例便是如此。

  • 请注意不同数据类型的语法
    • 第 10 行中的 10.2(小数点,而非逗号)。请注意屏幕上显示的是 10.2。
    • 第 13 行中的 1.4e-2(科学记数法)。屏幕上显示的数值为 0.014
    • [#01/10/2002#](第 26 行)表示 2002 年 1 月 10 日。因此 VBScript 使用格式 #mm/dd/yyyy# 来表示年 yyyy mm 日 dd
    • 第 31 行和第 34 行中的布尔值 true 和 false。如第 32 行和第 35 行的输出所示,这两个值分别由整数 -1 和 0 表示。当布尔值与字符串进行连接时,这些值会分别变为字符串 "True" 和 "False",如第 33 行和第 36 行所示。 请注意,连接运算符 & 不仅可以用于连接字符串。
  • 由于变量 v 未被指定类型,因此它可以随时间推移依次存储不同类型的值。

3.5. L : Variant 类型的子类型

以下是官方文档对变体可能包含的不同数据类型的说明:

除了简单的数字与字符串的区分之外,Variant 还可以区分不同类型的数值信息。例如,某些数值信息代表日期或时间。当这些信息与其他日期或时间数据结合使用时,结果始终以日期或时间的形式表示。 此外,还有其他类型的数值信息,范围从布尔值到大型浮点数。Variant 可以包含的这些不同类别的信息被称为子类型。在大多数情况下,您只需将数据放入 Variant 中,它就会根据该数据以最合适的方式进行处理。

下表列出了 Variant 可以包含的不同子类型。

子类型
描述
Variant 未初始化。对于数值变量,其值为零;对于字符串变量,其值为空字符串 ("")。
Variant 故意包含错误的数据。
Boolean
包含 TrueFalse
Byte
包含 0 到 255 之间的整数。
Integer
包含 -32,768 到 32,767 之间的整数。
货币
-922,337,203,685,477.5808 到 922,337,203,685,477.5807。
长整型
包含 -2,147,483,648 到 2,147,483,647 之间的整数。
单精度
包含一个单精度浮点数,负值范围为 -3.402823E38 至 -1.401298E-45;正值范围为 1.401298E-45 至 3.402823E38。
双精度
包含一个双精度浮点数,负值的范围为 -1.79769313486232E308 到 -4.94065645841247E-324; 正值范围为 4.94065645841247E-324 至 1.79769313486232E308。
日期(时间)
包含一个数字,表示 100 年 1 月 1 日至 9999 年 12 月 31 日之间的日期。
字符串
包含一个长度可变的字符串,上限约为 20 亿个字符。
对象
包含一个对象。
Error
包含一个错误编号。

3.6. C :确定变体中包含的数据的确切类型

类型为 variant 的变量可能包含多种类型的数据。有时我们需要了解这些数据的确切性质。如果我们在程序中写 product = number1 \* number2,则假设 number1number2 都是数值。但有时我们无法确定,因为这些值可能来自键盘输入、文件或其他外部来源。 此时,我们必须验证 number1*number2* 中存储的数据性质。*typename(var)* 函数允许我们确定变量 var 中包含的数据类型。以下是一些示例:

程序
结果
var=1,type=Integer
var=two,type=String
var=True, type=布尔型
var=4.5,type=双精度
var=11/10/01,type=Date

另一个可能的函数是 vartype(var),它返回一个数字,表示变量 var 中所含数据的类型:

常量
描述
vbEmpty
0
空(未初始化)
vbNull
1
Null(无有效数据)
vbInteger
2
整数
vbLong
3
长整数
vbSingle
4
单精度浮点数
vbDouble
5
双精度浮点数
vbCurrency
6
货币
vbDate
7
日期
vbString
8
字符串
vbObject
9
自动化对象
vbError
10
错误
vbBoolean
11
布尔值
vbVariant
12
Variant(仅用于 Variant 数组)
vbDataObject
13
非自动化对象
vbByte
17
字节
vbArray
8192
数组

注意:这些常量由 VBScript 定义。因此,您可以在代码中的任何位置使用这些名称来代替实际值。

上述信息来自 VBScript 文档。这些内容有时可能不准确,这很可能是由于从 VB 文档中复制粘贴所致。VBScript 的 vartype 函数仅实现了上述描述中的一部分功能。

针对 vartype 重写的前一个程序,会产生以下结果:

程序
结果
var=1,type=2
var=two,type=8
var=True,type=11
var=4.5,type=5
var=11/10/01,type=7

3.7. D 声明脚本使用的变量

我们提到,声明脚本中使用的变量并非强制要求。在这种情况下,如果我们写:


1) somme=4
...
2) somme=smme+10

如果第 2 行中存在拼写错误(例如将“somme”写成“smme”),VBScript 不会报告错误。它会将“smme”视为一个新变量,并创建该变量,同时在第 2 行的上下文中将其初始化为 0 并加以使用。

此类错误往往难以发现。因此,建议在脚本开头使用 option explicit 指令强制执行变量声明。这样,每个变量在首次使用前都必须通过 dim 语句进行声明:


option explicit
...
dim somme
1) somme=4
...
2) somme=smme+10

在此示例中,VBScript 会提示第 2) 项中存在未声明的变量 smme,如下所示:

程序
结果
dim1.vbs(9, 1) Microsoft 运行时错误
 VBScript:未定义的变量:'smme'

虽然本文中的简短示例中大多未声明变量,但一旦我们开始编写第一个有实际意义的脚本,就必须声明这些变量。届时将系统地使用 Option Explicit 指令。

3.8. 的转换函数

VBScript 会根据上下文将变体数据转换为字符串、数字、布尔值等。大多数情况下,这种转换效果良好,但有时会导致意外结果,我们稍后将看到这一点。因此,您可能希望“强制”变体的数据类型。VBScript 提供了将表达式转换为各种数据类型的转换函数。以下是其中几个:

Cint (表达式)
将表达式转换为短整数
Clng (表达式)
将表达式转换为长整数
Cdbl (表达式)
将表达式转换为双精度浮点数
Csng (表达式)
将表达式转换为单精度浮点数 (single)
Ccur (表达式)
将表达式转换为货币

以下是一些示例:

程序
结果
var=4,code type=8,type name=String
var=4,代码类型=2,名称类型=整数
var=1000000,类型代码=8,类型名称=字符串
var=1000000,类型代码=3,类型名称=长整型
var=3.4e-5,类型代码=8,类型名称=字符串
var=0.000034,类型代码=5,类型名称=双精度
var=3.4e-5,type code=8,type name=String
var=0.000034,类型代码=4,类型名称=单精度
var=1000,45,类型代码=8,类型名称=字符串
var=1000,45,类型代码=6,类型名称=货币
var=14,类型代码=2,类型名称=整数
var=14,类型代码=8,类型名称=字符串
var=1000,45,类型代码=5,类型名称=双精度
var=1000,类型代码=2,类型名称=整数
var=1000,75,类型代码=5,类型名称=双精度
var=1001,类型代码=2,类型名称=整数

3.9. 键盘输入的数据

wscript 对象允许脚本获取通过键盘输入的数据。wscript.stdin.readLine 方法可读取通过键盘输入并经按“Enter”键确认的一行文本。读取到的这一行文本可赋值给变量。

程序
结果

请输入您的姓名:st
你好 st

评论:

  • 在结果列和第 [输入您的姓名:st] 行中,st 是用户输入的文本。

如果键盘输入的文本代表一个数字,它仍主要被视为一串字符,如下例所示:

程序
结果
输入一个数字:14
读取的数字=14,类型=字符串

如果该数字用于算术运算,VBScript 会自动将字符串转换为数字,但并非总是如此。让我们来看以下示例:

程序
结果
1
2
3
4
5
6
number1: 3
数字2:4
3+4=34
3-4=-1
3 × 4 = 12
3/4=0.75

从结果中可以看出,脚本的第 8 行并未按预期运行,因为(很遗憾)在 VBScript 中,+ 运算符有两种含义:两个数字的加法,或者两个字符串的连接(将两个字符串拼接在一起)。 我们之前看到,键盘输入的数字会被视为字符串,而 VBScript 会在需要时将其转换为数字。对于只能涉及数字的 -、*、/ 运算,它处理得正确;但对于同样可能涉及字符串的 + 运算符,它却未能正确处理。在此处,它默认我们是要进行字符串连接。

解决此问题的简单方法是在读取字符串后立即将其转换为数字,如下所示,这是对先前程序的改进:

程序
结果
number1: 3
number1=3,type=String
number1=3,type=Long
number2: 4
number2=4,type=String
number2=4,type=Long
3+4=7
3-4=-1
3 × 4 = 12
3/4=0.75

3.10. S 使用 inputBox 函数输入数据

您可能希望通过图形界面而非键盘输入数据。在这种情况下,请使用 inputBox 函数。该函数支持许多参数,但通常只使用前两个:

response = inputBox(message, title)

  • message:向用户提出的问题
  • title(可选):您为输入窗口设置的标题
  • response:用户输入的文本。如果用户在未作回应的情况下关闭了窗口,response 则为空字符串。

以下是一个示例,其中我们要求用户输入姓名和年龄。对于姓名,我们输入信息并点击“确定”。对于年龄,我们也输入信息,但点击“取消”。

程序
结果

3.11. 使用结构化对象

使用 VBScript 可以创建具有方法和属性的对象。为了简化说明,这里我们将展示一个仅包含属性而没有方法的对象。以一个人为例。他们拥有许多描述其特征的属性:身高、体重、肤色、眼色、发色等。我们将仅关注其中两项:姓名和年龄。在使用对象之前,必须先创建一个模板,以便构建这些对象。 在 VBScript 中,这通过来实现。Person 类可以定义如下:


class personne
    Dim nom,age
End class

正是 [Dim name, age] 语句定义了 Person 类的两个属性。要创建 Person 类的副本(称为实例),我们编写:

set personne1=new personne
set personne2=new personne

为什么不这样写

personne1=new personne
personne2=new personne

因为变量不能包含对象本身,它只能包含对象的内存地址。当你编写 set person1 = new person 时,会发生以下一系列操作:

  1. 创建了一个 Person 对象。这意味着为其分配了内存。
  2. Person 对象的地址被赋值给 person1 变量

此时,person1person2 变量的内存布局如下:

从修辞角度来说,我们可以将person1称为“人对象”。只要记住person1实际上是“人对象”的地址,而非“人对象”本身,我们就能接受这种修辞说法。

我们提到Person对象有两个属性:name和age。如何访问这些属性?正如前文所述,使用object.property这种写法。因此

person1.name 指代 person1 的姓名,person1.age 指代其年龄。以下是一个简短的程序来演示这一点:

程序
结果
p1=(dupont,18)

前面的程序可以修改如下:

程序
结果
name=dupont
年龄=18

这里我们使用了 with ... end with 结构,它允许我们在表达式中“提取”对象名称。 第 9–12 行和第 15–18 行中的 with p1 ... end with* 结构,使我们可以使用 .name 代替 p1.name*,使用 .age* 代替 p1.age*。这简化了在反复使用相同对象名称的指令中的编写工作。

3.12. 为变量赋值

有两种语句可用于将值赋给变量:

  1. variable=expression
  2. set 变量=表达式

形式 2 专用于结果为对象引用的表达式。对于所有其他类型的表达式,形式 1 更为合适。这两种形式的区别如下:

  • 在语句 variable=expression 中,变量 variable 接收一个值。如果 v1 和 v2 是两个变量,写成 v1=v2 会将 v1 的值赋给 v2。这会导致一个值在两个不同位置被复制。如果随后修改了 v2 的值,v1 的值将保持不变。
  • 在语句 `set variable=expression` 中,`variable` 被赋予一个对象的地址。如果 `v1` 和 `v2` 是两个变量,且 `v2` 是对象 `obj2` 的地址,那么写 `set v1=v2` 会将 `v1` 的值赋给 `v2`,即对象 `obj2` 的地址。 当脚本随后操作 v1 和 v2 时,被操作的并非 v1 和 v2 的“值”,而是 v1 和 v2 “指向”的对象——在本例中,即同一个对象。 我们说 v1 和 v2 是指向同一个对象的两个引用,通过 v1 或 v2 对其进行操作并无区别。换言之,修改 v2 所引用的对象,即会修改 v1 所引用的对象。

以下是一个示例:

程序
结果
i=4
j=4
i=4
j=5
p1.last_name=dupont
p1.age=18
p1.last_name=dupont
p1.age=19
p2.name=dupont
p2.age=19

3.13. E 表达式的求值

用于求值的主要运算符如下:

运算符类型
运算符
示例
算术
+,-,*,/
 
  
  
  
   
比较
<,<=
>, >=
=,<>
当 a 不等于 b 时,a<>b 为真
当 a 等于 b 时,a=b 为真
a 和 b 可以都是数字,也可以都是字符串。在后一种情况下,如果 string1 在字母顺序上排在 string2 之前,则 string1<string2。在字符串比较中,大写字母在字母顺序上排在小写字母之前。
  
   
逻辑
与、或、非、异或
此处的所有操作数均为布尔值。
如果 bool1 或 bool2 为真,则 bool1 或 bool2 为真
bool1 和 bool2 均为真时,bool1 and bool2 为真
当 bool1 为假时,not bool1 为真,反之亦然
当布尔值 bool1 或 bool2 中仅有一个为真时,bool1 xor bool2 为真
   
连接
&, +
不建议使用 + 运算符来连接两个字符串,因为这可能会与两个数字的加法混淆。因此,您应仅使用 & 运算符。

3.14. C :控制程序执行

3.14.1. E 条件执行操作

用于根据条件为真或假来执行操作的 VBScript 语句如下:

if 表达式 then
    真-操作-1
    真-操作-2
    ..
否则
    false-操作-1
    错误操作-2
    ...
end if
首先评估该表达式。该表达式必须返回布尔值。如果评估结果为真,则执行 then 代码块中的操作;否则,如果存在 else 代码块,则执行其中的操作。

以下是一个演示 if-then-else 语句不同变体的程序:

程序
结果
1
2
3
4
5
3 大于 0
3 大于 2
i=4
4 小于 10
i=3

注释:

  • 在 VBScript 中,您可以使用 instruction1:instruction2:... : instructionn 的形式,而不是将每条指令单独写在一行上。例如,第 10 行就使用了这一特性。

3.14.2. E 反复执行操作

具有已知迭代次数的循环

对于 i=start 到 end,步长为 step
    操作
下一步
  1. 此处的变量 i 称为循环变量。它可以取任何名称
  2. i 取值为 start
  3. 将 i 的值与 ifin 进行比较。如果 i <= ifin,则执行 for... next 之间的操作
  4. i 增加 ipas 的量(i = i + ipas)
  5. 我们回到上文的第 3 步。经过有限次数的迭代后,i 的值将超过 ifin。脚本继续执行 next 语句后的内容
  6. 如果增量 ipas 为负数,则步骤 3 中的条件会发生变化。只有当 i >= ifin 时,for...next 之间的操作才会被执行。
您可以随时使用 exit for 语句退出 for 循环。
迭代次数未知的循环
do while 条件
    操作
循环
  1. 评估条件表达式。如果为真,则执行 while...循环中的操作
  2. 已执行的操作可能已改变了条件表达式的值。流程返回上述第 1 步
  3. 当条件表达式变为假时,循环结束
您可以随时使用 exit do 语句退出 do-while 循环。

下面的程序说明了这些要点:

程序
结果

i=0,array[i]=10,sum=10
i=1,array(i)=20,sum=30
i=2,array(i)=30,sum=60
i=3,array(i)=40,sum=100
i=0,array(i)=10,sum=10
i=1,array(i)=20,sum=30
i=2,array(i)=30,sum=60
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
i=10
i=11
i=1
i=2
i=3
i=4
i=5
i=6

:在程序开发阶段,程序出现“循环”现象(即永远不会停止)的情况并不少见。通常,程序会执行一个无法验证其退出条件的循环,如下例所示:


' infinite loop
i=0
Do While 1=1
  i=i+1
  wscript.echo i
Loop
 
' another of the same kind
i=0
Do While true
  i=i+1
  wscript.echo i
Loop

如果你运行上述程序,第一个循环将永远不会自动停止。你可以通过按下键盘上的 CTRL-C(同时按住 CTRL 和 C 键)来强制其停止。

3.14.3. 结束程序执行

wscript.quit n 语句通过返回等于 n 的错误代码来终止程序。在 DOS 环境下,可以使用 if ERRORLEVEL n 语句来检查该错误代码,如果最后执行的程序返回的错误代码 >=n,则该语句的评估结果为 true。请看以下程序及其结果:

  
开始

程序运行后,立即执行以下三个DOS命令:

1
2
3
4
5
6
7
C:\>if ERRORLEVEL 5 echo 5

C:\>if ERRORLEVEL 4 echo 4
4

C: >if ERRORLEVEL 3 echo 3
3

DOS 命令 1 用于检查程序返回的错误代码是否 >=5。如果是,则显示 (echo) 5;否则,不显示任何内容。

DOS 命令 3 检查程序返回的错误代码是否大于等于 4。如果是,则显示 4;否则,不显示任何内容。

DOS 命令 5 检查程序返回的错误代码是否大于等于 3。如果是,则显示 3;否则,不显示任何内容。

根据显示的结果,我们可以推断出程序返回的错误代码是 4。

3.15. L s data arrays in a variant

在变体中xml-ph-0000@deepl.internal数据数组一个变体 T 可以包含一组值。此时我们称其为数组。数组 T 具有以下特性:

  • 我们使用语法 T(i) 访问数组 T 的第 i 个元素其中 i 是 0 到 n-1 之间的整数(若 T 包含 n 个元素,则称为索引)。
  • 数组 T 的最后一个元素的索引可通过表达式 ubound(T) 确定。此时,数组 T 的元素个数即为 ubound(T)+1。该数值通常被称为数组的大小。
  • 变量 T 可以使用语法 T=array() 初始化为空数组,也可以使用语法 T=array(element0, element1, ...., elementn) 初始化为一组元素
  • 可以向已创建的数组 T 中添加元素。为此,请使用语句 redim preserve T(N),其中 N 是数组 T 最后一个元素的新索引。此操作称为调整大小(redim)。关键字 preserve 表示在调整大小的过程中,必须保留数组的当前内容。如果不使用此关键字,则 T 将被调整大小,且其元素会被清空。
  • 数组 T 的元素 T(i) 属于 variant 类型,因此可以包含任何值,包括另一个数组。在这种情况下,表示法 T(i)(j) 指代数组 T(i) 的第 j 个元素。

以下程序演示了数组的这些特性:

程序
结果
数组 t1 有 5 个元素
t1(0)=1
t1(1)=-4.5
t1(2)=2
t1(3)=True
t1(4)=1/10/02
t1=1:-4.5:2:True:2002年1月10日
t1(5)=10:20:30
t1(5)(1)=20
t1=1 ~ -4.5 ~ 2
t1=:::

注释

  • 这里我们使用了一个名为 join 的函数,下文将对此进行详细说明。

3.16. 数组变量的

在 VBScript 中,还有另一种使用数组的方法:使用数组变量。与标量变量不同,此类变量必须使用 dim 语句进行声明。可以进行多种声明:

  • dim array(n) 声明一个包含 n+1 个元素的静态数组,元素编号从 0 到 n。此类数组无法调整大小
  • dim array() 声明一个空的动态数组。使用时必须通过 redim 语句调整其大小,这与包含数组的变体(variant)的处理方式相同
  • dim array(n,m) 声明一个包含 (n+1)*(m+1) 个元素的二维数组。数组的第 (i,j) 个元素表示为 array(i,j)。请注意这与变体的区别,在变体中,同一元素将表示为 array(i)(j)

为什么会有两种本质上非常相似的数组类型?VBScript 文档并未对此进行说明,也没有指出其中一种是否比另一种更高效。在接下来的示例中,我们将几乎完全使用变体(Variant)中的数组。不过值得注意的是,VBScript 源自 Visual Basic 语言,而 Visual Basic 本身包含类型化数据(整数、双精度、布尔值等)。 在这种情况下,如果我们需要使用实数数组,例如,数组变量将比变体变量更高效。此时,我们可以声明类似 dim array(1000) as double 的语句来声明一个实数数组,或者如果数组是动态的,则简单地声明 dim array() as double

以下是一个说明数组变量使用的示例:

程序
结果
数组 t1 有 5 个元素
t1(0)=1
t1(1)=-4.5
t1(2)=2
t1(3)=True
t1(4)=1/10/02
t1=1:-4.5:2:True:10/01/02
数组 t1 有 5 个元素
t2(0)=0
t2(1)(2)=30
t2=:::
t3(0,0)=0
t3(0,1) = 1
t3(1,0)=10
t3(1,1)=11

3.17. L :拆分与拼接函数

split 和 join 函数允许您将字符串转换为数组,反之亦然:

  • T 是一个数组,car 是一个字符串,则 join(T,car) 是一个由数组 T 的所有元素连接而成的字符串,每个元素之间用字符串 car 分隔。因此,join(array(1,2,3),"abcd") 将返回字符串 "1abcd2abcd3"
  • C 是一个由字符串 car 分隔的字段序列组成的字符串,则函数 split(C,car) 会返回一个数组,其元素即字符串 C 的各个部分。因此,split("1abcd2abcd3", "abcd") 将返回数组 (1,2,3)

以下是一个示例:

程序
结果

' 数组转字符串及反向转换

' 数组转字符串
array = array("one", 2, "three")
string = join(array, ",")
wscript.echo string

' 字符串 --> 数组
array2 = split(string, ",")
For i=0 To ubound(array2)
  wscript.echo array2(i)
Next


一、二、三

2

3.18. 字典

当我们知道数组 T 的某个元素的索引 i 时,就可以访问该元素。此时,可以通过 T(i) 这种表示法来访问它。有些数组的元素不是通过索引,而是通过字符串来访问的。此类数组的典型例子就是字典。当我们在《拉鲁斯词典》或《小罗伯特词典》中查阅某个单词的含义时,就是通过该单词来访问的。我们可以将这种字典表示为一个两列数组:

词1
描述1
词条2
描述2
词3
描述3
....
 

然后我们可以编写如下代码:

dictionary("word1") = "description1"

dictionary("word2") = "description2"

...

这与数组的工作原理类似,不同之处在于数组的索引不是整数而是字符串。这种类型的数组被称为字典(或关联数组、哈希表),而字符串索引则被称为字典键。在计算机领域,字典的使用极为普遍。我们每个人都有一张印有编号的社会保障卡。这个编号能唯一地识别我们,并提供访问我们相关信息的途径。 在“字典(‘键’)=‘信息’”这一模型中,“键”即为社会保障号码,“信息”则指社会保障系统中存储的所有关于我们的信息。

在 Windows 中,有一个名为“Scripting.Dictionary”的 ActiveX 对象,它允许您创建和管理字典。 ActiveX 对象是一种软件组件,它提供了一个接口,只要程序符合 ActiveX 对象标准,无论使用何种语言编写,均可调用该接口。因此,Scripting.Dictionary 对象不仅可用于 VBScript,还可用于 JavaScript、Perl、Python、C、C++、VB、VBA 等 Windows 编程语言。

1
使用以下语句创建一个 Scripting.Dictionary 对象
set dico=wscript.CreateObject("Scripting.Dictionary")
或者简写为
set dico=CreateObject("Scripting.Dictionary")
CreateObject 是 WScript 对象的一个方法,用于创建 ActiveX 对象的实例。第 2 版表明 wscript 可以是一个隐式对象。当无法将某个方法“解析”为某个对象时,WSH 容器将尝试将其解析为 wscript 对象。
2
创建字典后,我们可以使用 add 方法向其中添加元素:
dico.add "key",value
这将在字典中创建一个与键 "key" 关联的新条目。关联的 value 是一个 Variant 类型,其中可以包含任意数据。
3
要检索与给定键关联的值,我们使用字典的 item 方法:
var = dic.item("key")
或者 如果该键对应的值是一个对象,则使用 set var = dic.item("key")
4
可以使用 `keys` 方法将字典中的所有键存入一个变量数组中:
keys = dic.keys
`keys` 是一个数组,其元素可以被遍历。
5
可以使用 `items` 方法将字典中的所有值存入一个变量数组中:
values = dic.items
`items` 是一个数组,其元素可以被迭代。
6
可以使用 `exists` 方法检查键是否存在:
如果字典中存在键 "key",则 dico.exists("key") 返回 true
7
可以使用 remove 方法从字典中删除一个条目(键+值):
dico.remove("key") 会从字典中移除与键 "key" 关联的条目。 dico.removeall 会移除所有键,即清空字典。

以下程序使用了这些不同的选项:

程序


' creating and using a dictionary
Set dico=CreateObject("Scripting.Dictionary")
 
' dico filling
dico.add "clé1","valeur1"
dico.add "clé2","valeur2"
dico.add "clé3","valeur3"
 
' number of elements
wscript.echo "Le dictionnaire a " & dico.count & " éléments"
 
' kEY LIST
wscript.echo "liste des clés"
cles=dico.keys
For i=0 To ubound(cles)
  wscript.echo cles(i)
Next
 
' list of values
wscript.echo "liste des valeurs"
valeurs=dico.items
For i=0 To ubound(valeurs)
  wscript.echo valeurs(i)
Next
 
' list of keys and values
wscript.echo "liste des clés et valeurs"
cles=dico.keys
For i=0 To ubound(cles)
  wscript.echo "dico(" & cles(i) & ")=" & dico.item(cles(i))
Next
 
' item search
' key1
If dico.exists("clé1") Then
    wscript.echo "La clé clé1 existe dans le dictionnaire et la valeur associée est " & dico.item("clé1")
  Else
    wscript.echo "La clé clé1  n'existe pas dans le dictionnaire"
  End If
' key4
If dico.exists("clé4") Then
    wscript.echo "La clé clé4 existe dans le dictionnaire et la valeur associée est " & dico.item("clé4")
  Else
    wscript.echo "La clé clé4  n'existe pas dans le dictionnaire"
  End If
 
' remove key 1
dico.remove("clé1")
 
' list of keys and values
wscript.echo "liste des clés et valeurs après suppression de clé1"
cles=dico.keys
For i=0 To ubound(cles)
  wscript.echo "dico(" & cles(i) & ")=" & dico.item(cles(i))
Next
 
' we do away with everything
dico.removeall
 
' list of keys and values
wscript.echo "liste des clés et valeurs après suppression de tous les éléments"
cles=dico.keys
For i=0 To ubound(cles)
  wscript.echo "dico(" & cles(i) & ")=" & dico.item(cles(i))
Next
 
' end
wscript.quit 0

结果

Le dictionnaire a 3 éléments
liste des clés
clé1
clé2
clé3
liste des valeurs
valeur1
valeur2
valeur3
liste des clés et valeurs
dico(clé1)=valeur1
dico(clé2)=valeur2
dico(clé3)=valeur3
La clé clé1 existe dans le dictionnaire et la valeur associée est valeur1
La clé clé4  n'existe pas dans le dictionnaire
liste des clés et valeurs après suppression de clé1
dico(clé2)=valeur2
dico(clé3)=valeur3
liste des clés et valeurs après suppression de tous les éléments

3.19. 对数组或字典进行排序

通常需要按数组或字典的值(对于字典则按键)升序或降序进行排序。虽然大多数编程语言都提供了排序函数,但VBScript中似乎没有。这是其一个缺陷。

3.20. 程序参数

可以通过向 VBScript 程序传递参数来调用它,例如:

cscript prog1.vbs arg1 arg2 .... argn

这允许用户向程序传递信息。程序如何获取这些信息?让我们来看以下程序:

程序
结果
C:\>cscript arg1.vbs a b c

有 3 个参数
a
b
c

注释

  • WScript.Arguments 是传递给脚本的参数集合
  • C 集合是一个具有
    • 一个 count 属性,表示集合中的元素个数
    • 一个方法 C(i),用于返回集合中的第 i 个元素

3.21. 第一个应用:TAXES

我们建议编写一个程序来计算纳税人的税额。我们考虑一个简化的情况:纳税人只需申报工资收入:

  • 员工的份额数按以下方式计算:nbParts = nbEnfants / 2 + 1(若员工未婚),或 nbEnfants / 2 + 2(若员工已婚),其中 nbEnfants 表示子女数。
  • 其应税收入 R = 0.72 * S,其中 S 为其年薪
  • 计算其家庭系数 Q = R / N

根据以下数据计算其应纳税额 I

12620.0
0
0
13,190
0.05
631
15,640
0.1
1,290.5
24,740
0.15
2,072.5
31,810
0.2
3,309.5
39,970
0.25
4,900
48,360
0.3
6,898.5
55,790
0.35
9,316.5
92,970
0.4
12,106
127,860
0.45
16,754.5
151,250
0.50
23,147.5
172,040
0.55
30,710
195,000
0.60
39,312
0
0.65
49,062

每行有 3 个字段。要计算税款 I,我们寻找第一个满足 QF <= 字段1 的行。例如,如果 QF = 30000,我们将找到该行

    24740        0.15        2072.5

此时,Tax I 等于 0.15*R - 2072.5*nbParts。如果 QF 使得条件 QF<=field1 永远不成立,则使用最后一行中的系数。这里:

    0                0.65        49062

由此可得税额 I = 0.65*R - 49062*nbParts。

程序如下:

程序

' calculating a taxpayer's tax liability
' the program must be called with three parameters: married children salary
' married: character Y if married, N if unmarried
' children: number of children
' salary: annual salary without cents

' no verification of data validity is performed, but we do
' check that there are three of them

' mandatory variable declaration
Option Explicit

' we check that there are 3 arguments
Dim nbArguments
nbArguments=wscript.arguments.count
If nbArguments<>3 Then
    wscript.echo "Syntaxe : pg marié enfants salaire"
    wscript.echo "marié : caractère O si marié, N si non marié"
    wscript.echo "enfants : nombre d'enfants"
    wscript.echo "salaire : salaire annuel sans les centimes"
    ' stop with error code 1
    wscript.quit 1
End If

' retrieve arguments without checking their validity
Dim marie, enfants, salaire
If wscript.arguments(0) = "O" Or wscript.arguments(0)="o" Then
    marie=true
Else
    marie=false
End If
' children is an integer
enfants=cint(wscript.arguments(1))
' salary is a long integer
salaire=clng(wscript.arguments(2))

' we define the data needed to calculate the tax in 3 tables
Dim limites, coeffn, coeffr
limites=array(12620,13190,15640,24740,31810,39970,48360, _
55790,92970,127860,151250,172040,195000,0)
coeffr=array(0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45, _
0.5,0.55,0.6,0.65)
coeffn=array(0,631,1290.5,2072.5,3309.5,4900,6898.5,9316.5, _
12106,16754.5,23147.5,30710,39312,49062)

' the number of shares is calculated
Dim nbParts
If marie=true Then
    nbParts=(enfants/2)+2
Else
    nbParts=(enfants/2)+1
End If
If enfants>=3 Then nbParts=nbParts+0.5

' we calculate the family quotient and taxable income
Dim revenu, qf
revenu=0.72*salaire
qf=revenu/nbParts

' tax calculation
Dim i, impot
i=0
Do While i<ubound(limites) And qf>limites(i)
    i=i+1
Loop
impot=int(revenu*coeffr(i)-nbParts*coeffn(i))

' the result is displayed
wscript.echo "impôt=" & impot

' leave without error
wscript.quit 0

结果

C:\>cscript impots1.vbs o 2 200000

impôt=22504

C:\>cscript impots1.vbs o 2 20000

impôt=0

C:\>cscript impots1.vbs o 2 2000000

impôt=746064

C:\>cscript impots1.vbs n 2 200000

impôt=33388

C:\>cscript impots1.vbs n 3 200000

impôt=22504

C:\>cscript impots1.vbs

Syntaxe : pg marié enfants salaire
marié : caractère O si marié, N si non marié
enfants : nombre d'enfants
salaire : salaire annuel sans les centimes

注释:

  • 该程序运用了之前学过的内容(变量声明、参数、类型转换、条件判断、循环、变体中的数组)
  • 它不检查数据的有效性,这在实际程序中是不常见的
  • 只有 while 循环具有一定难度。 它试图确定 limits 数组中满足 limits(i) > qf 的索引 i,且条件为 i < ubound(limits)(即此处 i < 13),因为 limits 数组的最后一个元素无关紧要。该元素仅被添加,以便能够对 i=13 执行条件 [Do While i<ubound(limits) And qf>limits(i)]。 此时条件变为 13<13 且 qf>limits(13),因此(在 VBScript 中)limits(13) 必须存在。退出 while 循环时,将使用最后计算出的 i 值来计算税额:[tax = Int(income * coeffr(i) - nbParts * coeffn(i))]。