Exact details of how Empty works in VBScript - vbscript

I'm new to VBScript and rather perplexed as to why the following code works:
set Adapters = GetObject("winmgmts:").InstancesOf("Win32_NetworkAdapterConfiguration")
for each Nic in Adapters
if Nic.IPEnabled then
MsgBox "IP Address: " & Nic.IPAddress(asdf), 4160, "IP Address"
end if
next
When the variable asdf is undefined, it works. If I define asdf to an invalid index (e.g. -1 or 4), I get an invalid index error.
I thought: Perhaps undefined variables default to 0 in VBS? Nope, I tried to print it and nothing is written.
Where is the functionality of passing an undefined variable as an array index returning the first item in the array documented? What are some other, similar oddities I may run into while programming in VBScript?
Edit: Some things I've discovered:
Undefined variables are equal to Empty by default in VBScript
Empty = 0 is true
Nic.IPAddress(Empty) also returns the first element of the array
MsgBox 0 will print 0, while MsgBox Empty will print nothing
I'm still having trouble finding any documentation stating that array indexing handles Empty quietly by returning the first element, explaining why it is equivalent to but printed differently from 0, and what other constructs handle Empty parameters (and what they do as a result).

The undefined variable is Empty and returning the Empty index of an array will also return the 0 index.
In the IPAddress array, there are two indexes, a 0 and a 1.
So this will have the same effect as your code:
MsgBox "IP Address: " & Nic.IPAddress(0), 4160, "IP Address"
And
MsgBox "IP Address: " & Nic.IPAddress(Empty), 4160, "IP Address"
And this will give you the IPv6 addresses:
MsgBox "IP Address: " & Nic.IPAddress(1), 4160, "IP Address"
Also, this will return both indexes of the array:
WScript.Echo Join(Nic.IPAddress,",")
Also, consider this example,
arr = Array("first","second","third")
WScript.Echo arr(Empty)
The output here will be first
See this post for VBScript Data Types:
"Empty : Variant is uninitialized. Value is 0 for numeric variables or a zero-length string ("") for string variables.`
http://msdn.microsoft.com/en-us/library/9e7a57cf(v=vs.84).aspx

Big thanks to Langstrom for providing this:
"Empty: Variant is uninitialized. Value is 0 for numeric variables or a zero-length string ("") for string variables."
Empty:
Nic.IPAddress(asdf) treats the parameter as an int, and CInt(Empty) is equal to 0, the index of the first element of the array.
MsgBox asdf treats the parameter as a string, and CStr(Empty) returns an empty string.
Any function that expects an integer and for which 0 is a valid value will work exactly the same as if 0 had been passed when called with an Empty parameter.
When comparing Empty = 0, Empty is treated as an integer because it being compared to an integer, so the expression is true.
When comparing Empty = "0", Empty is treated as a string, and so the expression is false. Therefore, Empty = "" is true.
Null:
Also, it is worth mentioning that Null is not equal to anything, including itself. Null = Null is false.

Related

Search a string in VBScript to verify if contains a character

I am trying to see if a string contains a dot.
Set Root_Currency = Root_TaxDataSummary.SlvObject("Currency")
curr_val = InStr(Root_Currency,".")
If curr_val.exist Then
pass
else
fail
Is there anything wrong with the way I am going about this?
InStr returns an integer representing the position the searched text can be found in the string.
curr_val.exist won't work because the integer type doesn't have an exist method. Instead:
If curr_val > 0 Then
Or (if this is the only use of that variable):
If InStr(Root_Currency,".") > 0 Then
Lastly, because 0 is treated as False in VBScript, you don't need to include the equality. Either a position is found for the character or you get back a 0/false:
If InStr(Root_Currency,".") Then
InStr returns a 'simple' number (1 based index/position of needle in haystack, or 0 meaning 'not found', or Null meaning Null argument) not an object. So change your code to:
If curr_val Then
' found
Else
' not found
End If

Error 800a01a8 Object Required for String

Why does this string need to be declared as an object when comparing to Nothing?
Dim BlankStr
BlankStr = "blank"
If BlankStr Is Nothing Then
End If
I also cannot compare If 1 Is 1 Then. Why can't I compare primitives?
VBScript has data (sub) types. Besides simple (sub) types like Strings:
>> x = "blank"
>> WScript.Echo VarType(x), TypeName(x)
>>
8 String
there are Objects:
>> Set y = New RegExp
>> WScript.Echo VarType(y), TypeName(y)
>>
9 IRegExp2
To assign an object to a variable, you need Set, to compare objects, you need Is. Simple (non-object) values have their own comparison operator.
To compare a string against another:
>> WScript.Echo CStr(x = "blank"), CStr(x = "object")
>>
True False
Trying to use a simple value 'as if it were an object', throws an "object required" error:
>> Set z = "blank"
>>
Error Number: 424
Error Description: Object required
>> WScript.Echo CStr(x Is x)
>>
Error Number: 424
Error Description: Object required
Read A Whole Lot Of Nothing.
String is not an object in VBScript.
So if you compare any primitive data types, you just use = to compare if they are equal. If does not require objects.
http://www.w3schools.com/asp/vbscript_ref_functions.asp
According a comment to this answer, VBScript doesn't have a string type. Instead it sounds like strings are primitives. Is works with object references.

Classic ASP InStr() Evaluates True on Empty Comparison String

I ran into an issue with the Classic ASP VbScript InStr() function. As shown below, the second call to InStr() returns 1 when searching for an empty string in a non empty string. I'm curious why this is happening.
' InStr Test
Dim someText : someText = "So say we all"
Dim emptyString : emptyString = ""
'' I expect this to be true
If inStr(1,someText,"so",1) > 0 Then
Response.write ( "I found ""so""<br />" )
End If
'' I expect this to be false
If inStr(1, someText, emptyString, 1) > 0 Then
Response.Write( "I found an empty string<br />" )
End If
EDIT:
Some additional clarification: The reason for the question came up when debugging legacy code and running into a situation like this:
Function Go(value)
If InStr(1, "Option1|Option2|Option3", value, 1) > 0 Then
' Do some stuff
End If
End Function
In some cases function Go() can get called with an empty string. The original developer's intent was not to check whether value was empty, but rather, whether or not value was equal to one of the piped delimited values (Option1,Option2, etc.).
Thinking about this further it makes sense that every string is created from an empty string, and I can understand why a programming language would assume a string with all characters removed still contains the empty string.
What doesn't make sense to me is why programming languages are implementing this. Consider these 2 statements:
InStr("so say we all", "s") '' evaluates to 1
InStr("so say we all", "") '' evaluates to 1
The InStr() function will return the position of the first occurrence of one string within another. In both of the above cases, the result is 1. However, position 1 always contains the character "s", not an empty string. Furthermore, using another string function like Len() or LenB() on an empty string alone will result in 0, indicating a character length of 0.
It seems that there is some inconsistency here. The empty string contained in all strings is not actually a character, but the InStr() function is treating it as one when other string functions are not. I find this to be un-intuitive and un-necessary.
The Empty String is the Identity Element for Strings:
The identity element I (also denoted E, e, or 1) of a group or related
mathematical structure S is the unique element such that Ia=aI=a for
every element a in S. The symbol "E" derives from the German word for
unity, "Einheit." An identity element is also called a unit element.
If you add 0 to a number n the result is n; if you add/concatenate "" to a string s the result is s:
>> WScript.Echo CStr(1 = 1 + 0)
>> WScript.Echo CStr("a" = "a" & "")
>>
True
True
So every String and SubString contains at least one "":
>> s = "abc"
>> For p = 1 To Len(s)
>> WScript.Echo InStr(p, s, "")
>> Next
>>
1
2
3
and Instr() reports that faithfully. The docs even state:
InStr([start, ]string1, string2[, compare])
...
The InStr function returns the following values:
...
string2 is zero-length start
WRT your
However, position 1 always contains the character "s", not an empty
string.
==>
Position 1 always contains the character "s", and therefore an empty
string too.
I'm puzzled why you think this behavior is incorrect. To the extent that asking Does 'abc' contain ''? even makes sense, the answer has to be "yes": All strings contain the empty string as a trivial case. So the answer to your "why is this happening" question is because it's the only sane thing to do.
It is s correct imho. At least it is what I expect that empty string is part of any other string. But maybe this is a philosophical question. ASP does it so, so live with it. Practically speaking, if you need a different behavior write your own Method, InStrNotEmpty or something, which returns false on empty search string.

How to display variable name not its value in vb

I am trying to get the variable name used in for each loop printed in vbs but unable to do so.
x=2, y=3, z=7
a = array (x,y,z)
for each element in a
wscript.echo element
next
The above example prints the variable element value (2/3/7) rather than element name (x/y/z). how do you i get to print the element name.
Please Help!
Did you consider using a dictionary?
Dim dict : Set dict = CreateObject("Scripting.Dictionary")
dict.item("x") = 2
dict.item("y") = 3
dict.item("z") = 7
dim key, value
For Each key in dict.Keys
value = dict.item(key)
wscript.echo key & " = " & value
Next
You can't in normal programming. You are the programmer, you know the names. You put the names in the output (msgbox "Variable name is A " & A).
You can put your code into strings, process it how you want, then execute it with eval or execute (see Help).
You can do the above but use the script control (see Google).
But you know the names, and if you want to display them simply, then you type their names into the message strings.
x=2, y=3, z=7
a = array (x,y,z)
names = array ("x","y","z")
for each element in names
wscript.echo element
next
If you want to show each element with his value:
x=2, y=3, z=7
a = array (x,y,z)
names = array ("x","y","z")
for i=0 to 2
wscript.echo names(i) & "=" & a(i)
next

QTP: Object Required errors when Object is valid

I have the following VBScript in a reusable action:
'Gather links
Browser("1").Navigate "http://InternalWebmail/something/inbox.nsf"
set oDesc = Description.Create()
oDesc("micclass").Value = "Link"
set links = Browser("1").Page("Webmail").ChildObjects(oDesc)
Dim links2
links2 = ""
'Filter out irrelevant links
For i = 0 To links.Count-1
If lcase(trim(links(i).GetROProperty("text"))) = lcase(trim(DataTable("ExpectedFrom", dtGlobalSheet))) Then
links2 = links2 + "," + links(i).GetROProperty("url")
End If
Next
Dim final
final = split(mid(links2,2),",") 'Remove leading comma and split into array
'For each link (i.e. for each E-mail received):
'Effectively giving a reusable action an input parameter, I hope
For i = 0 To final.Count - 1 'error: Object Required
DataTable("url","CheckHeader") = final(i)
RunAction "CheckHeader", oneIteration
Next
Everything runs just fine, until I get to the declaration of the loop at the bottom of the snippet. There, QTP gives me an error "Object Required" and refuses to elaborate.
i has a leading value of 58, though I've tried setting it to 0 prior to entering the loop.
final is an array of 6 strings, each a URL. All have a value.
If I msgbox(final(2)), I see the value of final(2) as being valid.
isobject(final(1)) = false
final(1) has the correct value
msgbox(final is nothing) and msgbox(final(1) is nothing) yield the same error.
It looks as if the array is null but somehow the array has members?
How is this possible?
What is QTP talking about?
In vbscript arrays don't have a Count property, you should use UBound
x = split("how now brown cow")
' MsgBox x.Count ' error
MsgBox UBound(x) ' 3
The reason .Count worked for the first loop is that ChildObjects does not return an array, it returns a COM collection object. That is also why you had to use the Set statement when assigning to links but not when assigning to final.

Resources