I am relatively new to ASP and VBScript, and I have a program that I'm working on that would be much easier with a map. However, after doing some searching, I can't find anything about a map in VB.
Is there a way to have something like the C++ map <Key, Value> in VBScript?
I would prefer to avoid downloading external resources. If not, whats the best alternative? Right now I just have a very large Select statement.
The name for Map in VBScript is Dictionary. Then docs are here
Sample code:
Select approach :
>> a = Array(1, 2, 3)
>> For Each e In a
>> Select Case e
>> Case 1
>> e = "alpha"
>> Case 2
>> e = "beta"
>> Case 3
>> e = "gammay"
>> End Select
>> WScript.Echo e
>> Next
>>
alpha
beta
gammay
Dictionary approach :
>> Set d = CreateObject("Scripting.Dictionary")
>> d(1) = "alpha"
>> d(2) = "beta"
>> d(3) = "gamma"
>> For Each e In d
>> WScript.Echo d(e)
>> Next
>>
alpha
beta
gamma
As you can see, the key type of a VBScript Dictionary is not restricted to String; numbers, dates, ..., and even objects work just as well. Another difference: the order of the key-value-pairs in a Dictionary is stable and reflects the order of entry.
Related
I am trying to make a randomizer that will pick an action out of 5. But here's the problem, when I run the script it doesn't pick an action out of the five. It just runs the action on line 3. Here's the script that I've done:
Randomize
a=Int((5 * Rnd()) + 1)
If a=5 then dim result
result = msgbox("Are you sure you want to install?", 4 , "Select yes or no")
If a=4 then c="Yes"
If a=3 then c="No"
If a=2 then c="Maybe"
If a=1 then c="Ask Me Later"
b=inputbox("What Is Your Question?")
c=msgbox("" & c)
Those lines of code is suppose to be an oracle of sorts, with a secret.
Edit:
God, this is embarassing:
Actually I tested you code just now, aaaaand: it works fine for me. Sooo maybe you should specify your problem again?!
Answer with Select Case
Randomize()
a=Int((5 * Rnd()) + 1)
Select Case a
Case 1
c= "Ask Me Later"
Case 2
c= "Maybe"
Case 3
c = "No"
Case 4
c = "Yes"
Case 5
dim result
result = msgbox("Are you sure you want to install?", 4 , "Select yes or no")
End Select
b = Inputbox("What Is Your Question?")
c = MsgBox("" & c)
Your code is using a single line If..Then statement, which you cannot have multiple actions assigned to. Try this:
Randomize
a=Int((5 * Rnd()) + 1)
If a=5 then
dim result
result = msgbox("Are you sure you want to install?", 4 , "Select yes or no")
End If
If a=4 then c="Yes"
If a=3 then c="No"
If a=2 then c="Maybe"
If a=1 then c="Ask Me Later"
b=inputbox("What Is Your Question?")
c=msgbox("" & c)
It's worth noting (as in other answers and comments) that where you have multiple If statements, it's often better to use a select case statement like this (I've also renamed the variables for easier readability):
Randomize
randomNum=Int((5 * Rnd()) + 1)
Select Case(randomNum)
Case 1 : randomResponse = "Ask Me Later"
Case 2 : randomResponse = "Maybe"
Case 3 : randomResponse = "No"
Case 4 : randomResponse = "Yes"
Case 5 : Dim result
result = MsgBox("Are you sure you want to install?", 4, "Select Yes or No") ' this option seems unwanted given your desired behaviour
End Select
userQuestion=InputBox("What Is Your Question?")
' should probably do something with userQuestion
' if it's empty you still return the random answer from above
' so only return the response where it's not
If Len(userQuestion)> 0 Then
MsgBox(randomResponse) ' don't need to append an empty string or set it to anything
End If
I am trying to sort the "fields" in a hash.
For example,
mykey, cde, firstone
mykey, abcde, secondone
mykey, bcde, thirdone
I want to sort the fields(cde, abcde, bcde) in alphabet order, but there is no way to do so.. If anyone knows about this, please help me.
If there is no way to solve this, I am thinking about changing names of key&values.. and use zadd instead of hash. If you have a better solution, please give me an advice here.
Hash field names are not sortable-by easily - there is no native command to do so and the order in which fields are returned (e.g. with HGETALL) is for all intents and purposes random.
While Sorted Sets are preferable when it comes to sorting, you could work around this with use of a Lua script that will perform lexical sorting the Hash's fields. For example:
$ cat hashsort.lua
local r = redis.call('HGETALL',KEYS[1])
local t = {}
for i=1,#r,2 do
t[#t+1] = { field = r[i], value = r[i+1] }
end
table.sort(t, function(a,b) return a.field < b.field end)
r = {}
for _, v in pairs(t) do
r[#r+1] = v.field
r[#r+1] = v.value
end
return r
$ redis-cli HMSET hash z 99 ee 55 e 5 a 1 b 2 ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ justsomethinglongsohashmaxzipwillbeexceeded
OK
$ redis-cli --eval hashsort.lua hash
1) "a"
2) "1"
3) "b"
4) "2"
5) "e"
6) "5"
7) "ee"
8) "55"
9) "z"
10) "99"
11) "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
12) "justsomethinglongsohashmaxzipwillbeexceeded"
I'm new to VBScript and I am running into some trouble. The script is making an API call and pulling account information, placing the data into a CSV file. I'm pulling the data into an array, looping through each account and, if certain properties qualify, assigning them to a variable to be written to the CSV. The problem I am having is if one account qualifies for a property, it sets the variable and if the next account doesn't qualify, the variable is still retaining the value, giving false results in the CSV.
Set SFTPServer = WScript.CreateObject("SFTPCOMInterface.CIServer")
accounts = SFTPServer.AdminAccounts
For each admin in accounts
adminName = admin.Login
Dim count : count = admin.GetPermissionsCount()
For i = 0 To CInt(count )- 1
Set permission = admin.GetPermission(i)
' AdminPermissionsPolicy:
' ServerManagement = 0,
' SiteManagement = 1,
' STManagement = 2,
' UserCreation = 3,
' ChangePassword = 4,
' COMManagement = 5,
' ReportManagement = 6,
Select case permission.Permission
case 0:
serverAdmin = "Server Admin"
case 1:
site = permission.SiteName
case 2:
stMan = "2"
case 3:
userCreate = "3"
case 4:
chPassword = "4"
case 5:
comMan = "5"
case 6:
report = "6"
End Select
Next
WriteStuff.WriteLine""+adminName+"|"+site+"|"+stMan+"|"+userCreate+"|"+chPassword+"|"+comMan+"|"+report+"")
Next
Unfortunately variables in VBScript are either at global, or function scope.
So you'll need to reset each of the variables on each iteration of the for loop.
One way would be to write Dim dummy at the top of your script, and just before the Select Case, write serverAdmin = dummy, site = dummy etc.
It's good practice to Dim explicitly all your variables, and to use Option Explicit at the top of the module to enforce that.
Here's an alternate way to do what you need without having to empty each variable on each iteration. You've already documented what each value means in your code. Instead of using comments for that purpose, define them as constants at the top of your scope block:
' AdminPermissionsPolicy:
Const ServerManagement = 0
Const SiteManagement = 1
Const STManagement = 2
Const UserCreation = 3
Const ChangePassword = 4
Const COMManagement = 5
Const ReportManagement = 6
Then you can declare an array to hold the values:
Dim a(6)
And then in your loop you can empty the array on each iteration using the Erase function. You can use the constant names instead of 0/1/2/etc and, when it comes time to write the values, you can use Join() to combine your array values into a string instead of having to concatenate 7 variables.
For each admin in accounts
adminName = admin.Login
Erase a ' Empty the Permissions array for each new account
Dim count : count = admin.GetPermissionsCount()
For i = 0 To CInt(count )- 1
Set permission = admin.GetPermission(i)
Select case permission.Permission
case ServerManagement: ' Now you can use the constant instead of "0"
a(ServerManagement) = "Server Admin"
case SiteManagement:
a(SiteManagement) = permission.SiteName
...
End Select
Next
WriteStuff.WriteLine Join(a, "|") ' Use Join() to combine array values
Next
Let's start with the output. You want to print a list of items (some of them possibly Empty) separated by "|". That should be done like this:
WriteStuff.WriteLine Join(aOut, "|")
Advantages:
You don't need to know that VBScript's concatenation operator is &, not +, because you can't even use the wrong one with Join.
You don't need to repeat the separator.
No useless pre/ap-pending of the empty string "".
Works with any number of items.
aOut needs to be initalized in the loop. That is easy with ReDim - without Preserve.
Advantages:
You don't need to know that Empty is the literal for empty/uninitialzed in VBScript.
You don't need to repeat an assignment for each variable.
Works with any number of items.
Demo code:
Option Explicit
Const cnUB = 3
Dim nTest
For nTest = 0 To cnUB
ReDim aOut(cnUB)
Select Case nTest
Case 0
aOut(0) = "A"
Case 1
aOut(1) = "B"
Case 2
aOut(2) = "C"
Case 3
aOut(3) = "D"
End Select
WScript.Echo Join(aOut, "|")
Next
output:
cscript 31565794.vbs
A|||
|B||
||C|
|||D
Disadvantage:
Putting the data into the array anonymously (just known by number/index) may be more errorprone than using distinct variable( name)s. If you need the elements for further computations it may be a good idea to define constants
wtf
Const ciReport = 1
...
aOut(ciReport) = "B"
When I do an intersection of two arrays, is there any guarantee that the resulting order is based on the order of the first array?
For example, if I have
a = [1,2,3]
b = [3,2,1]
could a & b return [3,2,1], instead of [1,2,3] (which is what I'd expect)?
I can't find anything directly addressing this in either RDoc's or the Pickaxe's documentation of Array.
RubySpec has a specification that it creates an array with elements in order they are first encountered, but should I assume YARV Ruby will honour that specification?
Looks like it is a guaranteed feature. They upgraded the RDoc description in revision 39415. It should be reflected sometime.
YARV is official Ruby interpreter since version 1.9, so I assume it doeas honour that specification. And BTW, RubySpec was created as executable specification of the language, allowing developers to create their own interpreters that pass this spec and I believe that YARV was created with this in RubySpec in mind.
There is no guarantee in the documentation but intersection follows the left-hand set's order.
The source shows that array a sets the order:
...
for (i=0; i<RARRAY_LEN(ary1); i++) {
vv = (st_data_t)(v = rb_ary_elt(ary1, i));
if (st_delete(RHASH_TBL(hash), &vv, 0)) {
rb_ary_push(ary3, v);
}
}
...
It's simple to test:
a = [1,2,3]
b = [3,2,1]
a.size.times do
puts "a = #{ a.join(',') }\ta & b = #{ (a & b).join(',') }\tb & a = #{ (b & a).join(',') }"
a.rotate!
end
Which outputs:
a = 1,2,3 a & b = 1,2,3 b & a = 3,2,1
a = 2,3,1 a & b = 2,3,1 b & a = 3,2,1
a = 3,1,2 a & b = 3,1,2 b & a = 3,2,1
That's using Ruby 1.9.3-p374
For example, if I have the following code:
dim a
if a = 0 then
b = 1
else
b = 2
end if
Can I shorten this code without sacrificing its validity? Thanks.
AFAIK , there is no way to shorten this code directly, but there you can do as :
dim a,b : a =0 : b=1 ''set a = 0 & b = 1 directly
'' Now as per your requirement 'a' value might change in script flow then you can set value as
If a > 0 then b= 2
Hope this help.........
You could use the single-line syntax for the If...Then...Else statement:
If a = 0 Then b = 1 Else b = 2
For this specific case, you could write a helper function to mimic the VBA IIf function:
Function IIf(expr, truepart, falsepart)
If expr Then
IIf = truepart
Else
IIf = falsepart
End If
End Function
b = IIf(a=0, 1, 2)
The basic If block is the simplest conditional statement in VBScript. VBScript does not have support for a Ternary Operator.