С гит-хаба был стырен кусок кода:
Dictionary
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
Option Explicit
#Const UseScriptingDictionaryIfAvailable = True
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Private dict_pKeyValues As Collection
Private dict_pKeys() As Variant
Private dict_pItems() As Variant
Private dict_pObjectKeys As Collection
Private dict_pCompareMode As CompareMethod
#Else
Private dict_pDictionary As Object
#End If
Public Enum CompareMethod
BinaryCompare = VBA.vbBinaryCompare
TextCompare = VBA.vbTextCompare
DatabaseCompare = VBA.vbDatabaseCompare
End Enum
Public Property Get CompareMode() As CompareMethod
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
CompareMode = dict_pCompareMode
#Else
CompareMode = dict_pDictionary.CompareMode
#End If
End Property
Public Property Let CompareMode(Value As CompareMethod)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Count > 0 Then
Err.Raise 5
End If
dict_pCompareMode = Value
#Else
dict_pDictionary.CompareMode = Value
#End If
End Property
Public Property Get Count() As Long
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Count = dict_pKeyValues.Count
#Else
Count = dict_pDictionary.Count
#End If
End Property
Public Property Get Item(Key As Variant) As Variant
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Dim dict_KeyValue As Variant
dict_KeyValue = dict_GetKeyValue(Key)
If Not IsEmpty(dict_KeyValue) Then
If VBA.IsObject(dict_KeyValue(2)) Then
Set Item = dict_KeyValue(2)
Else
Item = dict_KeyValue(2)
End If
Else
End If
#Else
If VBA.IsObject(dict_pDictionary.Item(Key)) Then
Set Item = dict_pDictionary.Item(Key)
Else
Item = dict_pDictionary.Item(Key)
End If
#End If
End Property
Public Property Let Item(Key As Variant, Value As Variant)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Exists(Key) Then
dict_ReplaceKeyValue dict_GetKeyValue(Key), Key, Value
Else
dict_AddKeyValue Key, Value
End If
#Else
dict_pDictionary.Item(Key) = Value
#End If
End Property
Public Property Set Item(Key As Variant, Value As Variant)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Exists(Key) Then
dict_ReplaceKeyValue dict_GetKeyValue(Key), Key, Value
Else
dict_AddKeyValue Key, Value
End If
#Else
Set dict_pDictionary.Item(Key) = Value
#End If
End Property
Public Property Let Key(Previous As Variant, Updated As Variant)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Dim dict_KeyValue As Variant
dict_KeyValue = dict_GetKeyValue(Previous)
If Not VBA.IsEmpty(dict_KeyValue) Then
dict_ReplaceKeyValue dict_KeyValue, Updated, dict_KeyValue(2)
End If
#Else
dict_pDictionary.Key(Previous) = Updated
#End If
End Property
Public Sub Add(Key As Variant, Item As Variant)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Not Me.Exists(Key) Then
dict_AddKeyValue Key, Item
Else
Err.Raise 457
End If
#Else
dict_pDictionary.Add Key, Item
#End If
End Sub
Public Function Exists(Key As Variant) As Boolean
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Exists = Not IsEmpty(dict_GetKeyValue(Key))
#Else
Exists = dict_pDictionary.Exists(Key)
#End If
End Function
Public Function Items() As Variant
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Count > 0 Then
Items = dict_pItems
Else
Items = VBA.Split("")
End If
#Else
Items = dict_pDictionary.Items
#End If
End Function
Public Function Keys() As Variant
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Count > 0 Then
Keys = dict_pKeys
Else
Keys = VBA.Split("")
End If
#Else
Keys = dict_pDictionary.Keys
#End If
End Function
Public Sub Remove(Key As Variant)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Dim dict_KeyValue As Variant
dict_KeyValue = dict_GetKeyValue(Key)
If Not VBA.IsEmpty(dict_KeyValue) Then
dict_RemoveKeyValue dict_KeyValue
Else
Err.Raise 32811
End If
#Else
dict_pDictionary.Remove Key
#End If
End Sub
Public Sub RemoveAll()
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Set dict_pKeyValues = New Collection
Erase dict_pKeys
Erase dict_pItems
#Else
dict_pDictionary.RemoveAll
#End If
End Sub
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Private Function dict_GetKeyValue(dict_Key As Variant) As Variant
On Error Resume Next
dict_GetKeyValue = dict_pKeyValues(dict_GetFormattedKey(dict_Key))
Err.Clear
End Function
Private Sub dict_AddKeyValue(dict_Key As Variant, dict_Value As Variant, Optional dict_Index As Long = -1)
If Me.Count = 0 Then
ReDim dict_pKeys(0 To 0)
ReDim dict_pItems(0 To 0)
Else
ReDim Preserve dict_pKeys(0 To UBound(dict_pKeys) + 1)
ReDim Preserve dict_pItems(0 To UBound(dict_pItems) + 1)
End If
Dim dict_FormattedKey As String
dict_FormattedKey = dict_GetFormattedKey(dict_Key)
If dict_Index >= 0 And dict_Index < dict_pKeyValues.Count Then
Dim dict_i As Long
For dict_i = UBound(dict_pKeys) To dict_Index + 1 Step -1
dict_pKeys(dict_i) = dict_pKeys(dict_i - 1)
If VBA.IsObject(dict_pItems(dict_i - 1)) Then
Set dict_pItems(dict_i) = dict_pItems(dict_i - 1)
Else
dict_pItems(dict_i) = dict_pItems(dict_i - 1)
End If
Next dict_i
dict_pKeys(dict_Index) = dict_Key
If VBA.IsObject(dict_Value) Then
Set dict_pItems(dict_Index) = dict_Value
Else
dict_pItems(dict_Index) = dict_Value
End If
dict_pKeyValues.Add Array(dict_FormattedKey, dict_Key, dict_Value), dict_FormattedKey, Before:=dict_Index + 1
Else
If VBA.IsObject(dict_Key) Then
Set dict_pKeys(UBound(dict_pKeys)) = dict_Key
Else
dict_pKeys(UBound(dict_pKeys)) = dict_Key
End If
If VBA.IsObject(dict_Value) Then
Set dict_pItems(UBound(dict_pItems)) = dict_Value
Else
dict_pItems(UBound(dict_pItems)) = dict_Value
End If
dict_pKeyValues.Add Array(dict_FormattedKey, dict_Key, dict_Value), dict_FormattedKey
End If
End Sub
Private Sub dict_ReplaceKeyValue(dict_KeyValue As Variant, dict_Key As Variant, dict_Value As Variant)
Dim dict_Index As Long
Dim dict_i As Integer
dict_Index = dict_GetKeyIndex(dict_KeyValue(1))
dict_RemoveKeyValue dict_KeyValue, dict_Index
dict_AddKeyValue dict_Key, dict_Value, dict_Index
End Sub
Private Sub dict_RemoveKeyValue(dict_KeyValue As Variant, Optional ByVal dict_Index As Long = -1)
Dim dict_i As Long
If dict_Index = -1 Then
dict_Index = dict_GetKeyIndex(dict_KeyValue(1))
End If
If dict_Index >= 0 And dict_Index <= UBound(dict_pKeys) Then
For dict_i = dict_Index To UBound(dict_pKeys) - 1
dict_pKeys(dict_i) = dict_pKeys(dict_i + 1)
If VBA.IsObject(dict_pItems(dict_i + 1)) Then
Set dict_pItems(dict_i) = dict_pItems(dict_i + 1)
Else
dict_pItems(dict_i) = dict_pItems(dict_i + 1)
End If
Next dict_i
If UBound(dict_pKeys) = 0 Then
Erase dict_pKeys
Erase dict_pItems
Else
ReDim Preserve dict_pKeys(0 To UBound(dict_pKeys) - 1)
ReDim Preserve dict_pItems(0 To UBound(dict_pItems) - 1)
End If
End If
dict_pKeyValues.Remove dict_KeyValue(0)
dict_RemoveObjectKey dict_KeyValue(1)
End Sub
Private Function dict_GetFormattedKey(dict_Key As Variant) As String
If VBA.IsObject(dict_Key) Then
dict_GetFormattedKey = dict_GetObjectKey(dict_Key)
ElseIf VarType(dict_Key) = VBA.vbBoolean Then
dict_GetFormattedKey = IIf(dict_Key, "-1__-1", "0__0")
ElseIf VarType(dict_Key) = VBA.vbString Then
dict_GetFormattedKey = dict_Key
If Me.CompareMode = CompareMethod.BinaryCompare Then
Dim dict_Lowercase As String
dict_Lowercase = ""
Dim dict_i As Integer
Dim dict_Char As String
Dim dict_Ascii As Integer
For dict_i = 1 To VBA.Len(dict_GetFormattedKey)
dict_Char = VBA.Mid$(dict_GetFormattedKey, dict_i, 1)
dict_Ascii = VBA.Asc(dict_Char)
If dict_Ascii >= 97 And dict_Ascii <= 122 Then
dict_Lowercase = dict_Lowercase & dict_Char
Else
dict_Lowercase = dict_Lowercase & "_"
End If
Next dict_i
If dict_Lowercase <> "" Then
dict_GetFormattedKey = dict_GetFormattedKey & "__" & dict_Lowercase
End If
End If
Else
dict_GetFormattedKey = VBA.CStr(dict_Key) & "__" & CStr(dict_Key)
End If
End Function
Private Function dict_GetObjectKey(dict_ObjKey As Variant) As String
Dim dict_i As Integer
For dict_i = 1 To dict_pObjectKeys.Count
If dict_pObjectKeys.Item(dict_i) Is dict_ObjKey Then
dict_GetObjectKey = "__object__" & dict_i
Exit Function
End If
Next dict_i
dict_pObjectKeys.Add dict_ObjKey
dict_GetObjectKey = "__object__" & dict_pObjectKeys.Count
End Function
Private Sub dict_RemoveObjectKey(dict_ObjKey As Variant)
Dim dict_i As Integer
For dict_i = 1 To dict_pObjectKeys.Count
If dict_pObjectKeys.Item(dict_i) Is dict_ObjKey Then
dict_pObjectKeys.Remove dict_i
Exit Sub
End If
Next dict_i
End Sub
Private Function dict_GetKeyIndex(dict_Key As Variant) As Long
Dim dict_i As Long
For dict_i = 0 To UBound(dict_pKeys)
If VBA.IsObject(dict_pKeys(dict_i)) And VBA.IsObject(dict_Key) Then
If dict_pKeys(dict_i) Is dict_Key Then
dict_GetKeyIndex = dict_i
Exit For
End If
ElseIf VBA.IsObject(dict_pKeys(dict_i)) Or VBA.IsObject(dict_Key) Then
ElseIf dict_pKeys(dict_i) = dict_Key Then
dict_GetKeyIndex = dict_i
Exit For
End If
Next dict_i
End Function
#End If
Private Sub Class_Initialize()
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Set dict_pKeyValues = New Collection
Erase dict_pKeys
Erase dict_pItems
Set dict_pObjectKeys = New Collection
#Else
Set dict_pDictionary = CreateObject("Scripting.Dictionary")
#End If
End Sub
Private Sub Class_Terminate()
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Set dict_pKeyValues = Nothing
Set dict_pObjectKeys = Nothing
#Else
Set dict_pDictionary = Nothing
#End If
End Sub
А в другом модуле идёт инициализация этого класса
типа так
1.
2.
3.
4.
5.
6.
Public Function CreateKeyValue(Key As String, Value As Variant) As Dictionary
Dim web_KeyValue As New Dictionary
web_KeyValue("Key") = Key
web_KeyValue("Value") = Value
End Function
И вот такое обращение:
см.: web_KeyValue("Key")
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
Public Function ConvertToUrlEncoded(Obj As Variant, Optional EncodingMode As UrlEncodingMode = UrlEncodingMode.FormUrlEncoding) As String
Dim web_Encoded As String
Dim i As Integer
If TypeOf Obj Is Collection Then
Dim web_KeyValue As Dictionary
For Each web_KeyValue In Obj
If VBA.Len(web_Encoded) > 0 Then: web_Encoded = web_Encoded & "&"
web_Encoded = web_Encoded & web_GetUrlEncodedKeyValue(web_KeyValue("Key"), web_KeyValue("Value"), EncodingMode)
Next web_KeyValue
Else
Dim web_Key As Variant
For Each web_Key In Obj.Keys()
If Len(web_Encoded) > 0 Then: web_Encoded = web_Encoded & "&"
web_Encoded = web_Encoded & web_GetUrlEncodedKeyValue(web_Key, Obj(web_Key), EncodingMode)
Next web_Key
End If
ConvertToUrlEncoded = web_Encoded
End Function
И вот то ли я тупой, то ли незнаю... Подскажите, как мне дописать модуль класса чтобы работали эти конструкции?
Может, у кого есть готовый? Я так понимаю, этот класс часто используется...