vba Scripting.Dictionary

本文详细介绍了Microsoft编程语言(如VisualBasic、VBScript和Jscript)中的Dictionary对象,包括其基本概念、成员概要、操作方法以及属性。通过实际代码示例展示了如何在VBScript和JScript中使用Dictionary对象,包括增加、删除条目,修改键或条目的值,设置比较模式,以及遍历Dictionary对象。此外,提供了全局.asa文件和示例页面的使用方法,帮助开发者更好地理解和利用Dictionary对象提高编程效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

一,定义 

 

   许多Microsoft的编程语言,如Visual Basic、VBScript和Jscript,都提供集合(collection)。可以把集合想象为数组,可以使用其中内建的函数完成存储和操纵数据等基本任务。无须担心数据是在哪些行列,而是使用唯一的键进行访问。
  VBScript和Jscript都提供类似的对象,通称Scripting.Dictionary对象或Dictionary对象。它类似于二维数组,把键和相关条目的数据存放在一起。然而真正的面向对象的方法,不应直接访问数据条目,必须使用Dictionary对象支持的方法和属性来实现。

1. Dictionary对象的成员概要
  当增加一个键/条目对时,如果该键已存在;或者删除一个键/条目对时,该关键字/条目对不存在,或改变已包含数据的Dictionary对象的CompareMode,都将产生错误。
  属性说明
  CompareMode (仅用于VBScript)设定或返回键的字符串比较模式
  Count 只读。返回Dictionary里的键/条目对的数量
  Item(key) 设定或返回指定的键的条目值
  Key(key) 设定键值

  方法说明
  Add(key,item) 增加键/条目对到Dictionary
  Exists(key) 如果指定的键存在,返回True,否则返回False
  Items() 返回一个包含Dictionary对象中所有条目的数组
  Keys() 返回一个包含Dictionary对象中所有键的数组
  Remove(key) 删除一个指定的键/条目对
  RemoveAll() 删除全部键/条目对

2. 对Dictionary中增加和删除条目
  一旦得到一个新的(空的)Dictionary,可以对其添加条目,从中获取条目以及删除条目:
  ‘ In VBScript:
  objMyData.Add “MyKey”, “MyItem”
  objMyData.Add “YourKey”, ”YourItem”
  blnIsThere = objMyData.Exists(“MyKey”)
  strItem = objMyData.Item(“YourKey”)
  strItem = objMyData.Remove(“MyKey”)
  objMyData.RemoveAll

3. 修改键或条目的值
  可以通过修改键的值,或通过修改与特定的键关联的条目的数据,来改变存储在Dictionary内的数据。下面的代码改变键为MyKey的条目中的数据。
  ObjMyData.Item(“MyKey”) = “NewValue” ‘ In VBScript
  ObjMyData.Item(‘MyKey’) = ‘NewValue’; // In JScript
  如果指定的键在Dictionary未找到,将在Dictionary中创建一个以MyKey为键,以New Value为其条目值的新的键/条目对。有意思的是,如果使用一个不存在的键来检索条目,不仅得到一个空的字符串(这是可以想到的),而且还在Dictionary里添加一个新的键/条目对,键即是指定的键,但条目的数据为空。
  可以使用Key属性仅改变键的值而不改变与之对应的条目的数据。将一个已存在的键MyKey改变为MyNewKey,可以用:
  objMyData.Key(“MyKey”) = “MyNewValue” ‘ In VBScript
  objMyData.Item(‘MyKey’) = ‘MyNewValue’; // In JScript
  如果指定的键未找到,则产生运行期错误。

4. 设置比较模式
  Dictionary的CompareMode属性仅适用于VBScript,不能在JScript中使用。当比较字符串键时,允许指定比较的方式。两个允许的值为BinaryCompare(0)和TextCompare(1)。BinaryCompare(0)为二进制数对照(即区分大小写);TextCompare(1)为文本对照(即不区分大小写)。

5. 遍历Dictionary
  研究Dictionary时,有两个方法和一个属性需要特别注意,它们允许我们遍历存储在Dictionary里的所有键/条目对。Items方法用一个一维数组的形式返回Dictionary里所有的条目数据,而keys方法用一个一维数组返回所有已存在的键值。可以使用Count属性得到键或条目的数量。
  例如,可以使用下列代码得到名称为objMyData的Dictionary中所有的键和条目值。注意,虽然Count属性保存了在Dictionary里的键/条目数量,但VBScript和JScript的数组总是从下标0开始的。因此,数组下标应从0到Count-1。
  ‘In VBScript:
  arrKeys = objMyData.Keys ‘Get all the keys into an array
  arrItems = objMyData.Items ‘Get all the items into an array

  For intLoop = 0 To objMyData.Count –1 ‘Iterate through the array
    StrThisKey = arrKeys(intLoop) ‘This is the key value
    StrThisItem = arrItems(intLoop) ‘This is the item (data) value
  Next

  // In JScript
  // Get VB-style arrays using the Keys() and Items() methods
  var arrKeys = new VBArray(objMyData.Keys()).toArray();
  var arrItems = new VBArray(objMyData.Items()).toArray();

  for (intLoop = 0; intLoop < objMyData.Count; intLoop++) {
    // Iterate through the arrays
    strThisKey = arrKeys[intLoop]; // This is the key value
    strThisItem = arrItems[intLoop]; // This is the item (data) value
  }
  在VBScript里也可以使用For Each … Next语句完成同样的功能:
  ‘ Iterate the dictionary as a collection in VBScript
  For Each objItem in arrItems
    Response.Write objItem & “ = “ & arrItems(objItem) & “<BR>”
  Next

5.3.2 Dictionary对象示例
  本书提供了一系列示例文件可用来试验脚本运行时间库的各种属性。
  本章代码的缺省页面提供了一系列可使用的VBScript示例链接。有些示例对JScript同样有效。这些示例存放在Chapter05目录下相应的子目录里

  要查看Dictionary对象的运行,在菜单页面点击第一个链接,打开名叫show_dictionary.asp的页面。这个页面显示了我们提供的Dictionary对象的内容,允许试验其属性和方法。屏幕如图5-3所示:

  1. Dictionary的global.asa文件
  随Dictionary对象示例页面提供的文件之一是global.asa。它创建并预先填充了一个会话层作用域的Dictionary对象,因此其内容在页面请求之间不会丢失。一般说来(考虑到可扩展性),这不是一个理想的做法。在这个例子里,可以看到Dictionary的属性和方法的效果。
  如果在自己的服务器上下载并安装示例,必须创建一个基于此global.asa文件的虚拟应用程序。或者将其内容添加到缺省站点的根文件夹中的global.asa文件里。在第3章讲述了如何用向导创建虚拟应用程序。然而对于本示例,创建一个虚拟应用程序最简单的方法是在Chapter05示例文件夹内右击dictionary子文件夹,在Properties对话框的Home Directory选项卡里,点击Create按钮,如图5-4所示:

  在这个global.asa文件里,代码使用<OBJECT>元素创建一个会话层作用域的Scripting.Dictionary对象实例。然后在Session_onStart事件处理程序里将一系列值用Add方法放入Dictionary中,并将对Dictionary对象的引用指定给ASP会话变量MyDictionary:
<OBJECT ID="objBookList" RUNAT="SERVER" SCOPE="SESSION" PROGID="Scripting.Dictionary"> </OBJECT>

<SCRIPT LANGUAGE="VBScript" RUNAT="SERVER">

  Sub Session_onStart()
    objBookList.Add "2610", "Professional Active Server Pages 3.0"
    objBookList.Add "1274", "Instant JavaScript"
    objBookList.Add "2882", "Beginning ASP Components"
    objBookList.Add "1797", "Professional ASP Techniques"
    objBookList.Add "1835", "AD0 2.0 Programmer's Reference"
    Set Session("MyDictionary") = objBookList
  End Sub

</SCRIPT>

2. Dictionary示例页面
  在“Scripting.Dictionary Object”主页面里,首要的任务是得到一个会话层作用域的Dictionary对象实例的引用。注意,这个引用是一个对象变量,因此必须在VBScript里使用Set关键字。
  然后,检查一下是否得到了一个对象(这是个好习惯),如果没有正确地建立包含global.asa文件的虚拟应用程序,检查一下问题出在哪里。你将看到我们自己的消息代替了ASP的错误消息(但是注意,对于这一操作必须关闭缺省的错误处理)。
<%

  on error resume next ' turn off error handling to test if object exists

  'retrieve Dictionary object from user's session
  Set objMyData = Session("MyDictionary")

  If IsObject(objMyData) Then 'found Dictionary object in Session

%>

  <P><DIV CLASS="subhead">Iterating the Dictionary with Arrays</DIV>
<%
  arrKeysArray = objMyData.Keys 'get all the keys into an array
  arrItemsArray = objMyData.Items 'get all the items into an array
  For intLoop = 0 To objMyData.Count - 1 'iterate through the array
    Response.Write "Key: <B>" & arrKeysArray(intLoop) & "</B> Value: <B>" _
            & arrItemsArray(intLoop)& "</B><BR>"
  Next
%>

… Other code and controls go here …

<%
Else

'could not find Dictionary object in the session
Response.Write "Dictionary object not available in global.asa for session"

End If
%>
显示在页面上的Dictionary内容列表是使用Dictionary对象的Key和Items方法创建的两个数组,可使用前面的代码遍历它们。
3. Dictionary页面控件
在Dictionary的内容列表下是一系列的HTML控件,可用于设定Dictionary对象的某些属性和执行各种方法。这些控件全部在一个<FORM>内,其ACTION属性值是本页面,所以窗体的内容提交回本页面。在前面的章节的示例里使用了同样的技术。
在<FORM>段中,改变属性或执行一个方法是通过一个按钮(没有标题)实现的。用于属性和方法的值放入按钮旁的文本框或列表框中。
该页的第一个按钮用于设定Dictionary里的条目的Key属性。这里使用了一个下拉列表,可以选择一个已经存在的Key值。下面的代码创建了页面内该部分的控件。为了填充列表,使用了另外一个遍历Dictionary对象的技术,即For Each … Next语句。代码如下:

<FORM ACTION="<% = Request.ServerVariables("SCRIPT_NAME") %>" METHOD="POST">

<P><DIV CLASS="subhead">The Dictionary Properties</DIV>
<INPUT TYPE="SUBMIT" NAME="cmdChangeKey" VALUE=" ">
Dictionary.Key ("
<SELECT NAME="lstChangeKey" SIZE="1">
<%
For Each objItem in objMyData
Response.Write "<OPTION>" & objItem
Next
%>
</SELECT> ") = "
<INPUT TYPE="TEXT" NAME="txtChangeKey" SIZE="15" VALUE="New Key Name"> "
<BR>

… Other controls go here …

</FORM>

4. 使用Dictionary的属性和方法
在“Scription.Dictionary Object”页面,点击用来检查并改变条目的Key属性的按钮,如图5-5所示:

把窗体再次提交给页面。该页面包含一个脚本段,检查被点击的按钮的值。它通过在Resquest.Form集合里查找按钮的名字来断定单击的是哪个按钮。如果发现一个对应于cmdChangKey的值,则从列表中或文本框中得到相应的值并用来改变Key属性:

'look for a command sent from the FORM section buttons
If Len(Request.Form("cmdChangeKey")) Then
strKeyName = Request.Form("lstChangeKey") 'Existing key from list box
strNewKey = Request.Form("txtChangeKey") 'New key value from text box
objMyData.Key(strKeyName) = strNewKey 'Set key property of this item
End If

页面重新载入后,在Dictionary的内容列表里能看到相应的结果,如图5-6所示:

页面的其余代码用来设定一个条目的Item属性,或者执行Dictionary对象的方法。下面是这些操作的代码,每段代码与演示Key属性的代码非常类似。每次都将结果显示在Dictionary的内容列表中:

If Len(Request.Form("cmdChangeItem")) Then
strKeyName = Request.Form("lstChangeItem") 'Existing key from list box
strNewValue = Request.Form("txtChangeItem") 'New item value from text box
objMyData.Item(strKeyName) = strNewValue 'Set the Item property
End If

If Len(Request.Form("cmdAdd")) Then
strKeyName = Request.Form("txtAddKey") 'New key value from text box
strItemValue = Request.Form("txtAddItem") 'New item value from text box
objMyData.Add strKeyName, strItemValue 'Execute the Add method
End If

If Len(Request.Form("cmdRemove")) Then
strKeyName = Request.Form("lstRemove") 'Existion key from list box
objMyData.Remove strKeyName 'Execute the Remove method
End If

If Len(Request.Form("cmdRemoveAll")) Then
objMyData.RemoveAll 'Execute the RemoveAll method
End If

例如,如果现在点击Add方法的按钮,在Dictionary的内容列表里将增加一个新的条目,如图5-7所示:

结果如图5-8所示:

可以在这个页面中试验Dictionary对象的属性和方法,你将会发现什么因素及在什么环境下能引起Dictionary对象错误。例如,尝试用与已经存在的一个条目相同的键值增加一个条目,看看会出现什么结果。

 

 -------------------------------------------------------------------------------------------------------------------

 

二,运用

VBA中Dictionary对象使用小结

Dim dict

' 创建Dictionary
Set dict = CreateObject("Scripting.Dictionary")

' 增加项目
dict.Add "A", 300
dict.Add "B", 400
dict.Add "C", 500

' 统计项目数
n = dict.Count

' 删除项目
dict.Remove ("A")

' 判断字典中是否包含关键字
dict.exists ("B")

' 取关键字对应的值,注意在使用前需要判断是否存在key,否则dict中会多出一条记录
Value = dict.Item("B")

' 修改关键字对应的值,如不存在则创建新的项目
dict.Item("B") = 1000
dict.Item("D") = 800

' 对字典进行循环

   Dim k() As Variant
   Dim v() As Variant
k = dict.keys
v = dict.Items
For i = 0 To dict.Count - 1
key = k(i)
Value = v(i)
MsgBox key & Value
Next

' 删除所有项目

dict.Removeall

实例:

Sub 宏1()

Set dic = CreateObject("Scripting.Dictionary") '字典
For i = 1 To 10000
If Not i Like "*4*" Then
dic.Add i, "" '如果不包含“1”
End If
Next
Range("a2").Resize(dic.Count, 1) = Application.WorksheetFunction.Transpose(dic.keys) '从A2单元开始向下放置
End Sub

 

 

 

=========================================================================

又 Tranpose工作表函数的用法实例

 

'把一行多列的二维数组转换成一维数组

Sub test()
Dim arr, arrt
arr = Range("a1:j1")
arrt = WorksheetFunction.Transpose(WorksheetFunction.Transpose(arr))
Stop
End Sub

首先看看TRANSPOSE函数的基础用法。官方帮助说明,TRANSPOSE函数可返回转置单元格区域,即将行单元格区域转置成列单元格区域,反之亦然。

  TRANSPOSE函数语法是:TRANSPOSE(array)

  Array参数是需要进行转置的数组或工作表上的单元格区域。所谓数组的转置就是,将数组的第一行作为新数组的第一列,数组的第二行作为新数组的第二列,以此类推。

 

 

 

 

 

 

 

 

下面这断VBA,运行报错“ByRef参数类型不符” Sub GenerateSQL() Dim inputStr As String Dim outputStr As String Dim wsData As Worksheet Dim wsMain As Worksheet Dim lastRow As Long Dim dict As Object Dim tables As Object Dim relations As Object ' 初始化对象 Set dict = CreateObject("Scripting.Dictionary") Set tables = CreateObject("Scripting.Dictionary") Set relations = CreateObject("Scripting.Dictionary") ' 设置工作表 Set wsMain = ThisWorkbook.Sheets("Sheet1") Set wsData = ThisWorkbook.Sheets("Sheet2") ' 假设数据结构在Sheet2 ' 读取数据结构 lastRow = wsData.Cells(wsData.Rows.Count, "A").End(xlUp).Row For i = 2 To lastRow Dim tableName As String Dim fieldEN As String Dim fieldCN As String Dim dataType As String fieldEN = wsData.Cells(i, 1).Value fieldCN = wsData.Cells(i, 2).Value dataType = wsData.Cells(i, 3).Value tableName = Split(fieldEN, "_")(0) ' 假设字段格式为 TableName_FieldName ' 存储字段映射 dict(fieldCN) = Array(tableName, fieldEN, dataType) ' 存储表结构 If Not tables.Exists(tableName) Then tables(tableName) = New Collection End If tables(tableName).Add fieldEN Next i ' 建立表关系(示例,需根据实际情况修改) relations.Add "Customers", Array("Orders", "CustomerID") ' 获取用户输入 inputStr = wsMain.Range("A1").Value ' 解析输入 Dim selectParts As New Collection Dim fromTable As String Dim whereClause As String Dim joinClause As String ' 基础解析(可根据需要扩展) Dim keywords As Variant keywords = Split(inputStr, " ") For Each word In keywords If dict.Exists(word) Then Dim fieldInfo As Variant fieldInfo = dict(word) ' 处理SELECT部分 selectParts.Add (fieldInfo(0) & "." & fieldInfo(1)) ' 确定主表 If fromTable = "" Then fromTable = fieldInfo(
03-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值