VBA "Left"-function as integer - vba

been playing around with the "left"-function in VBA and noticed that the result is stored as a string. For example:
Left(ws2.range("C2").value,3)
Where ws2 is some worksheet and c2 is some cell in ws2 containing, say, 1234.
The left function would then return "123" but it would be formated as a string. This in turn causes errors for me when i try to access a directories key with this string (which is not possible). I've found a workaround where I :
dim tag as integer
tag = Left(ws2.range("C2").value,3)
This would cause the tag with the value 123 to be stored as an integer which I then can use for accessing the directory.
But i'm wondering if it's possible to modify the "left"-function to return values as integers? or any other format for that matter (long, variant, range, whatever)
Notice that I have figured out a solution but I thought it might be helpful to others and/or a interesting discussion.

For this it is easiest to use Cint() function. There is no need to modify functions, you can always create yours.

The proper way to do it would be to use the Cint() function to cast an expression to an integer.
For details see https://msdn.microsoft.com/en-us/library/fctcwhw9(v=vs.84).aspx

Here are some more conversion functions:
CInt() 'convert to integer
CLng() 'convert to long (long is preferred over integer since integer only has 2 bytes in VBA)
CDbl() 'convert to double
CDec() 'convert to decimal (variable has to be declared as variant)

Made it an answer :)
cint(left(ws2.range("C2").value,3)) would be "better" as you're still relying on VBA to make the conversion for you, also checking the output first to work out if you in fact need to use a long maybe. Also checking the input string is numeric first of all would also be a good check.

using cint
function IntLeft(byval value as string, byval length as integer) as Integer
IntLeft=0 'default if non numeric
if isnumeric(value) then
IntLeft=cint(left(value,length))
end if
end function
using int
function IntLeft(byval value as string, byval length as integer) as Integer
IntLeft=int(left(value,length)) 'int returns the first numbers as an int, 0 if no numbers
end function

You can use Abs function instead to return the left function as integer.
i.e., Abs(Left(ws2.range("C2").value,3))

Related

"VBA.len" is 4 times slower than "len" (?!) [duplicate]

When I run the following macro:
Sub try()
Dim num As Integer
num = 123
MsgBox Len(num)
MsgBox VBA.Len(num)
End Sub
The first Msgbox displays 2 and the second Msgbox displays 3.
If I remove the first line which says Dim num As Integer, both MsgBoxes display 3.
Can anyone explain why?
Len and LenB are not just ordinary functions, they are keywords, and as such are found on the list of VBA keywords (although LenB is only mentioned after you click through to Len).
Mid would be another example of such keyword disguised as function, whereas e.g. Left isn't on the list at all, because that is just an ordinary function.
It has to be a keyword because one of its jobs is to perform the compile-time task of determining the storage size of a variable. E.g. with private user-defined types, an ordinary function could not do that at all:
Private Type foo
a As Long
b As String
End Type
Sub TestLens()
Dim f As foo
MsgBox Len(f) ' OK
MsgBox VBA.Len(f) ' Compile time error
End Sub
The fact that the object browser brings you to VBA.Len when you press Shift+F2 on that Len(f) is both correct and misleading.
The Len(f) here does not actually call the VBA.Len function that determines the string size, it simply cannot do that because it would require coercing a private struct into a Variant. Instead it calculates the size of foo at compile time and substitutes the result as a literal constant into the executable.
In your example the Len(num) calculates the compile-time size of variable num (which is 2) and substitutes the constant 2 into the resulting object code, whereas VBA.Len(num) packs the value of num into a Variant and passes that variant to VBA.Len where it's further converted to string "123" and the length of that is returned.
It has to do with the way that VB stores integers and how the Len() function handles arguments that are not strings.
When a datatype that is not a string is passed to the Len() function, it returns the nominal number of bytes used to store the data (VB uses 2 bytes to store an integer). See the documentation for the Len function.
The Len() function will automatically cast the variant variable (which is created by assigning a value to a variable without declaring it first) as a string. The return isn't changing because the storage allocation changes (although it does; variants require 16 bytes of storage space, minimum). Since the implicitly declared variable is actually a variant type, VB will automatically change its type based on the situation. In this case, Len() expects a string so VB makes the variable a string.
You could use Msgbox Len(Cstr(num)) to cast the integer variable as a string before passing it to the Len function if your intent is to return the number of characters in your integer value.

Why do Len and VBA.Len return different results?

When I run the following macro:
Sub try()
Dim num As Integer
num = 123
MsgBox Len(num)
MsgBox VBA.Len(num)
End Sub
The first Msgbox displays 2 and the second Msgbox displays 3.
If I remove the first line which says Dim num As Integer, both MsgBoxes display 3.
Can anyone explain why?
Len and LenB are not just ordinary functions, they are keywords, and as such are found on the list of VBA keywords (although LenB is only mentioned after you click through to Len).
Mid would be another example of such keyword disguised as function, whereas e.g. Left isn't on the list at all, because that is just an ordinary function.
It has to be a keyword because one of its jobs is to perform the compile-time task of determining the storage size of a variable. E.g. with private user-defined types, an ordinary function could not do that at all:
Private Type foo
a As Long
b As String
End Type
Sub TestLens()
Dim f As foo
MsgBox Len(f) ' OK
MsgBox VBA.Len(f) ' Compile time error
End Sub
The fact that the object browser brings you to VBA.Len when you press Shift+F2 on that Len(f) is both correct and misleading.
The Len(f) here does not actually call the VBA.Len function that determines the string size, it simply cannot do that because it would require coercing a private struct into a Variant. Instead it calculates the size of foo at compile time and substitutes the result as a literal constant into the executable.
In your example the Len(num) calculates the compile-time size of variable num (which is 2) and substitutes the constant 2 into the resulting object code, whereas VBA.Len(num) packs the value of num into a Variant and passes that variant to VBA.Len where it's further converted to string "123" and the length of that is returned.
It has to do with the way that VB stores integers and how the Len() function handles arguments that are not strings.
When a datatype that is not a string is passed to the Len() function, it returns the nominal number of bytes used to store the data (VB uses 2 bytes to store an integer). See the documentation for the Len function.
The Len() function will automatically cast the variant variable (which is created by assigning a value to a variable without declaring it first) as a string. The return isn't changing because the storage allocation changes (although it does; variants require 16 bytes of storage space, minimum). Since the implicitly declared variable is actually a variant type, VB will automatically change its type based on the situation. In this case, Len() expects a string so VB makes the variable a string.
You could use Msgbox Len(Cstr(num)) to cast the integer variable as a string before passing it to the Len function if your intent is to return the number of characters in your integer value.

How to convert one data type to another

I am a very novice VB.NET programmer. How do I convert one type to another?
Dim a as String="2"
Dim b as Integer='what?
There are several ways to convert a string to an integer.
You know the string contains a numeric:
Dim b as Integer = Integer.Parse(a)
If it is not a valid integer or contains non numerals, it can crash. Other value types (Decimal, Double) have the same method.
Pretty much the same:
Dim b as Integer= Convert.ToInt32(b)
You dont know if the string is clean or not. For instance this would be used to convert a value from a text box, where the user types "cat" as their age:
If Integer.TryParse(a, b) Then ...
The big difference here is that the return is a Boolean (True or False) telling you whether the parsing went ok. If not (False), tell the user to enter again; else (True) the second param will be the converted value. Date, Double, Decimal etc all have a TryParse method.
This answer provides a more detailed explanation.
Many of the "primitive" data types have several parsing methods that can construct from a string representation.
Check the Parse and TryParse shared methods of Integer.

Look for a method of WorksheetFunction which returns an Integer

I consider TypeName function returns the exact type of a data in VBA. Now I am looking for a WorksheetFunction which can return an Integer, instead of Double.
A lot of WorksheetFunction returns Double in VBA, for example, MsgBox TypeName(Application.WorksheetFunction.RandBetween(1, 2)) gives Double. Oddly some functions which are supposed to return an Integer give also Double, for example, MsgBox TypeName(Application.WorksheetFunction.Count(Range("A2:A10"))) and MsgBox TypeName(Application.WorksheetFunction.Fact(3)).
So does anyone know if there is a WorksheetFunction which returns a Double and can let TypeName detect it?
You can use the int() function to retrieve the output of one of the functions you mentioned in Integer format.

Left value of an integer

I have a value in variable, say it is dim a as integer = 145.98
I tried to take the Left(a,2)
but it returned an error instead of returning 14
I also tried left(a.Tostring,2)
but error is the same.
Please help me solve it.
Thanks
Furqan
First off, you say that you’re using an integer but the number is actually a floating-point number, not an integer.
Secondly, the action “take the left of a number” isn’t a meaningful operation. Left is a substring operation, it’s only defined on strings.
You can turn the number into a string and then extract a substring of the decimal representation. This should work. What’s the error?
Finally, some general advice:
Put Option Strict On at the very top of ever vb file, or better yet, make this option the default in your settings. Otherwise, you’ve got a veritable hullaballoo waiting to happen because VB is very … “lenient” when it comes to questionable or downright incorrect code. This option fixes this and will flag a lot more errors. For example, the compiler would (rightfully) have complained about your assignment,
Dim a As Integer = 145.98
because as I said, you’re trying to assign a floating-point number to an integer.
First of all, 145.98 is not an integer. 145 is an integer. You might want to try Double. Second, you can only take the left of a string. You were on the right track when you added ToString, but you forgot the ()s at the end.
Dim a as Integer = 145
Dim b as Double = 145.98
Then you can do this:
Left(a.ToString(), 2)
Left(b.ToString(), 2)
Try Left(a.ToString(), 2) instead.
If your "integer" is a string, try this:
Dim a As String = "145.98"
Dim b As Int32 = 0
Int32.TryParse(a.Substring(0, 2), b)
As Konrad has said with option strict this would not compile. If you don't have it on it will perform a conversion and store only the integer part. At this point you can call tostring and then performe any operation on it as a string you would like.
With option strict
Option Strict On
Module Module1
Sub Main()
Dim I As Integer = CType(142.3, Integer)
Dim s As String = I.ToString
Console.WriteLine(Left(s, 2))
End Sub
End Module
With out optiion strict
Module Module1
Sub Main()
Dim I As Integer = 142.3
Dim s As String = I
Console.WriteLine(Left(s, 2))
End Sub
End Module
As you can see from the two example option strict will attempt to perform many conversions for you but does so at the risk of unexpected results.