Usage of + operator in differents situations in vbscript - vbscript

What is the Value of the below in vbscript
1)x=1+"1"
2)x="1"+"1"
3)x=1+"mulla"
Note:In the all above three cases I am using first variable as either string or integer and second on as always as string.
Case 1:Acting as a numeric and auto conversion to numeric during operation
enter code here
y=inputbox("Enter a numeric value","") Rem I am using 1 as input
x=1
msgbox x+y Rem value is 2
msgbox x*y Rem value is 1
Case 2:Acting as a String and no conversion to numeric during operation it fails
enter code here
y=inputbox("Enter a numeric value","") Rem I am using 1 as input
x=1
if y= x then
msgbox "pass"
else
msgbox "fail"
end if
Case 3:Acting as a String and explicit conversion to numeric during operation it passes
enter code here
y=inputbox("Enter a numeric value","") Rem I am using 1 as input
x=1
if Cint(y) = x then
msgbox "pass"
else
msgbox "fail"
end if
I need a logic reason for the different behaviors. but in other language it is straight forward and will work as expected

Reference: Addition Operator (+) (VBScript)
Although you can also use the + operator to concatenate two character strings, you should use the & operator for concatenation to eliminate ambiguity. When you use the + operator, you may not be able to determine whether addition or string concatenation will occur.
The type of the expressions determines the behavior of the + operator in the following way:
If Both expressions are numeric then the result is the addition of both numbers.
If Both expressions are strings then the result is the concatenation of both strings.
If One expression is numeric and the other is a string then an Error: type mismatch will be thrown.
When working with mixed data types it is best to cast your variables into a common data type using a Type Conversion Function.

I agree with most of what #thomas-inzina has said but the OP has asked for a more detailed explanation so here goes.
As #thomas-inzina point's out using + is dangerous when working with strings and can lead to ambiguity depending on how you combine different values.
VBScript is a scripting language and unlike it's big brothers (VB, VBA and VB.Net) it's typeless only (some debate about VB and VBA also being able to be typeless but that's another topic entirely) which means it uses one data type known as Variant. Variant can infer other data types such as Integer, String, DateTime etc which is where the ambiguity can arise.
This means that you can get some unexpected behaviour when using + instead of & as + is not only a concatenation operator when being used with strings but also a addition operator when working with numeric data types.
Dim x: x = 1
Dim y: y = "1"
WScript.Echo x + y
Output:
2
Dim x: x = "1"
Dim y: y = "1"
WScript.Echo x + y
Output:
11
Dim x: x = 1
Dim y: y = 1
WScript.Echo x + y
Output:
2
Dim x: x = 1
Dim y: y = "a"
WScript.Echo x + y
Output:
Microsoft VBScript runtime error (4, 5) : Type mismatch: '[string: "a"]'

Related

VB Control Naming by Variable

Dim LineNo as Integer
LineNo = CStr(channel) 'This can have a value of 1 to 100
If LineNo = 1 then
Text1.Text = "Line one selected"
Elseif LineNo = 2 then
Text2.Text = "Line one selected"
'Etc etc
End if
I need to replace the number "1" in Text1.Text and every other TextBox with the value of LineNo? For example:
Text{LineNo}.Text
So I would not have to do a repeated "If" and have a smaller one line code like this:
Text{LineNo}.Text = "Line " & LineNo & " selected"
How would I do this?
Look into a Control array of text boxes. You could have txtLine(), for example, indexed by the channel number.
LineNo = CStr(channel)
txtLine(channel).Text = "Line " & LineNo & " selected"
To create the array, set the Index property of each of the text boxes to an increasing integer, starting at 0.
If you have a finite and relatively small number, you can use a property. I've used this approach with up to 30+ elements in a pinch. Super simple, easy pattern to recognize and replicate in other places. A bit if a pain if the number of elements changes in the future, but extensible nevertheless.
It uses the Choose statement, which takes an index N and returns the Nth element (1-based), hence, the check makes sure that N is > 0 and <= MAX (which you would configure).
Public Property Get TextBox txt(ByVal N As Long)
Const MAX As Long = 10
If N <= 0 || N > MAX Then Exit Property ' Will return a "Nothing". You could return the bound element if you prefer
set txt = Choose(Text1, Text2, Text3, Text4, Text5, Text6, Text7, Text8, Text9, Text10)
End Property
Then, you can simply reference them with the Property, much like an alias:
txt(1).Text = "Line 1 text"
txt(2).Text = "Line 2 text"
If you have an arbitrary number, then you are likely using a control array already, which is simpler because it can be referenced by Index already, so you can directly reference it.
If neither of these work for you and you have a very large number of controls, you can scan the Controls collection in a similar Property, attempting to match ctrl.Name with the pattern of your choice (e.g., matching the first 4 characters to the string "Text", thus matching Text1, Text2, etc, for an unlimited number). Theoretically, this should be future-proofed, but that's just theoretical, because anything can happen. What it does do for you is to encapsulate the lookup in a way that "pretends" to be a control array. Same syntax, just you control the value.
Public Property Get TextBox txt(ByVal N As Long)
Dim I As Long
For I = 0 To Controls.Count - 1 ' Controls is zero-based
' Perform whatever check you need to. Obviously, if you have a "Label" named
' "Text38", the assignment will throw an error (`TextBox = Label` doesn't work).
If Left(Controls(I).Name, 4) = "Text" Then
set txt = Controls(I)
End If
Next
' If you want the Property to never return null, you could uncomment the following line (preventing dereference errors if you insist on the `.Text` for setting/getting the value):
' If txt Is Nothing Then Set txt = Text1
End Property
Use the same way as above: txt(n).Text = "..."

Random Characters added to String

I am trying to add a random set of numbers to the end of a string. I'm still learning the basics of VBS but this has really tricked me and I can't seem to find anything online.
I've tried:
string2 = "hello" + (Rnd() * Len(VALID_TEXT)) + 1
And:
x = rnd*10
string2 = "hello" + x
What am I doing wrong?
All random number generators rely on an underlying algorithm, usually fed by what’s called a seed number. You can use the Randomize statement to create a new seed number to ensure your random numbers don’t follow a predictable pattern.
To get the random numbers, using rnd alone is not sufficient as you will keep on getting the same random number again and again. You have to use randomize to achieve the task as shown below:
Dim strTest:strTest = "Hello"
Dim intNoOfDigitsToAppend:intNoOfDigitsToAppend = 5
Randomize
Msgbox "String before appending: " & strTest
strTest = fn_appendRandomNumbers(strTest,intNoOfDigitsToAppend)
Msgbox "String before appending: " & strTest
function fn_appendRandomNumbers(strToAppend,intNoOfRandomDigits)
Dim i
for i=1 to intNoOfRandomDigits
strToAppend= strToAppend & int(rnd*10) 'rnd gives a random number between 0 and 1, something like 0.8765341. Then, we multiply it by 10 so that the number comes in the range of 0 to 9. In this case, it becomes 8.765341. After that, we use the int method to truncate the decimal part so that we are only left with the Integer part. In this case, 765341 is truncated and we are left with only the integer 8
next
fn_appendRandomNumbers = strToAppend
end function
Reference 1
Reference 2
& is the string concatenation character. + is an old compatability concat character and will error if you mix text and numbers. Use + for maths only.

VBS numerical const not working in >= comparison for loop [duplicate]

This question already has answers here:
VBScript implicit conversion in IF statement different from variable to literals?
(2 answers)
Closed 5 years ago.
I've run into a weird issue (IMHO) which may just be highlighting my ignorance when it comes to VBS vs. other programming languages. Here's what I have at the top of my .VBS file.
Option Explicit
Const MAXROWSFOREXCEL2010 = 1048576
I then have the following conditional check in a loop:
If numLines >= MAXROWSFOREXCEL2010 Then
wscript.echo "Inside the numLines If Then Statement"
wscript.echo "numLines = " & numLines & " >= " & MAXROWSFOREXCEL2010
As an example, let's say numLines is equal to 107563, which is clearly less than the 1 million plus value assigned to MAXROWSFOREXCEL2010 as a global const above.
For whatever reason, the IF statement is being executed, even when numLines is clearly less than the const.
However, if I remove the use of the const in the comparison, and just put the hard coded value of MAXROWSFOREXCEL2010 into the loop such as:
If numLines >= 1048576 Then
wscript.echo "Inside the numLines If Then Statement"
wscript.echo "numLines = " & numLines & " >= " & MAXROWSFOREXCEL2010
Then the IF statement is NOT entered incorrectly.
Can someone clue me in to why this is the case? Should I be somehow declaring the const as a particular data type? Is there some sort of truncation of the const going on?
I would be inclined to suggest the problem is numLines not being numeric rather than there being a problem with the Const value, in which case this question answers the problem.
From A:VBScript implicit conversion in IF statement different from variable to literals? by #cheran-shunmugavel
The documented behavior is that in comparisons, a number is always less than a string. This is mentioned in the documentation for Comparison Operators. Paraphrasing the table near the bottom of the page:
If one expression is numeric and the other is a string, then the numeric expression is less than the string expression.
With that in mind you simply need to make sure the variable numLines is explicitly a numeric value using an explicit cast.
'Explicitly cast variable to Long
numLines = CLng(numLines)
OK, I believe what's going on is a quirk of the way VBS attempts to determine data types. I also believe you're numLines variable is being evaluated as a String.
You can do Wscript.Echo TypeName(numLines) to verify this. I can replicate your issue when I set numLines equal to "107563" instead of 107563.
If a value is "boxed" in VBS, in the case of your const MAXROWSFOREXCEL2010, the engine will attempt to perform the comparison operation differently than if it's not. In this case, because numLines is a string and the comparison is against a boxed variable, it attempts to do a (bitwise) string comparison. If numLines is a string and the comparison is against an explicit Integer the comparison is done as a (bitwise) integer comparison.
If numLines was an Integer this problem doesn't happen.
Here are some more examples:
strOne = "1"
intOne = 1
If "1" = 1 Then WScript.Echo "true" Else WScript.Echo "false"
If "1" = intOne Then WScript.Echo "true" Else wscript.Echo "false"
If strOne = 1 Then WScript.Echo "true" Else wscript.Echo "false"
If strOne = intOne Then WScript.Echo "true" Else wscript.Echo "false"
Output
true
true
true
false

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.

VBS convert string to floating point

Dim strnumber
strnumber = "0.3"
Dim add
add = 0.1
Dim result
result = strnumber + add
MsgBox result
I want to get 0.4 as result, but get 3.1.
I tried clng(strnumber) and int(strnumber), nothing works. There is a simple solution for sure but I won't find it.
EDIT: Solution
result = CDbl(Replace(strnumber,".",",") + add
Has to do with your locale settings. Automatic conversion (as well as explicit one) observes it in the same manner as in CStr() function.
E.g. in my locale CStr( 0.3) results to 0,3 that is invert to CDbl("0,3") while CDbl("0.3") results to an error.
BTW: always use option explicit and, for debugging purposes, On Error Goto 0
Following below procedures can help:
Replacing the dot(".") with comma (",") in the string
change the string to double by Cdbl
example:
dim a,b,c
a="10.12"
b="5.05"
a=Replace(a,".",",")
b= Replace(b,".",",")
c=Cdbl(a)+Cdbl(b)
msgbox c
You want to add two numbers. So you should use numbers (and not a string (strnumber) and a number (add):
>> n1 = 0.3
>> n2 = 0.1
>> r = n1 + n2
>> WScript.Echo r
>>
0,4
As you can see from the output (0,4), I'm using a locale (German) that uses "," as decimal 'point'. But literals always use ".". So by using the proper data types you can write your scripts in a language/locale independent fashion as long as you don't need to process external string data (from a file or user input). Then you have to modify the input before you feed it to a conversion function like CDbl(). For simple cases that can be done with Replace(inp, badmarker, goodmarker).
P.S. You said you " tried clng(strnumber) and int(strnumber)". You should have tried CDbl(). CLng() tries to get a long integer (cf. CInt()), Int() removes/rounds the fraction from number.

Resources