how to dim a variable that has both numbers and letters? - excel

As I am new to Excel VBA, how to classify a variable that has both letters and numbers? Like for instance "f0rmym8" do I Dim As Long or Dim As String or something else?
Thanks!

As per the documentation the string type variable is the only one capable of holding characters. (with the exclusion of variant, being able to hold an array of strings). All other data types are practically purely numeric, including Date and Boolean in VBA, with Date being effectively a Double formatted as a date, and a Boolean being -1 (true) or 0 (false).
In summary whenever you need to hold any kind of ASCII character that is not numeric, you will need to use the string data type, regardless of whether there are also numeric characters present. A numeric data type is always incapable of holding any type of text.

A String can hold any group of characters, consider:
Sub catscradle()
Dim Letters As String, MixedStuff As String, JustNumerals As String
Dim NothingAtAll As String
Letters = "ABC"
MixedStuff = "1A2B3C"
JustNumerals = "0076941"
NothingAtAll = ""
End Sub

Related

VBA Strings without Dollar Signs

I'm learning about VBA, and I've noticed an odd quirk when VBA interacts with adding strings. When you take the two versions of code (Change the commented parts with the swap here commented parts) one outputs a string with a dollar sign, and one does without. Does anybody know if this is a bug or is planned to be upgraded?
Option Explicit
Sub CalcCost()
Dim curSalesPrice As Currency
Dim curTotalCost As Currency
Dim sngSalesTax As Single
Dim strMessage As String
curSalesPrice = 35
sngSalesTax = 0.085
Range("A1:B8").ClearContents
Range("A1").Value = "The cost of the calculator"
Range("A4").Value = "Price"
Range("B4").Value = curSalesPrice
Range("A5").Value = "SalesTax"
Range("A6").Value = "Cost"
Range("B5").Value = curSalesPrice * sngSalesTax
'curTotalCost = curSalesPrice + (curSalesPrice * sngSalesTax)
curTotalCost = Format(curSalesPrice + (curSalesPrice * sngSalesTax), "Currency") 'swap here
'strMessage = "The calculator total is " & Format(curTotalCost, "Currency")
strMessage = "The calculator total is " & curTotalCost 'swap here
Range("A8").Value = strMessage
Range("B6").Value = curTotalCost
End Sub
Format is a VBA standard library function defined in the VBA.Strings module; it returns a String representation of the expression it's given, formatted as specified: it makes no sense to do this:
Dim foo As Currency ' a numeric data type...
foo = Format(123, "Currency") ' ...assigned to a string representation of a numeric value
But it makes complete sense here:
Dim msg As String
msg = Format(123, "Currency")
Now, the value of a cell is distinct from its text representation. It's not because you see $123.00 in a cell that the value of that cell is $123.00 (a String); that's the cell's Text, but its Value can very well be 123 (a Double) and its NumberFormat be $#0.00.
You want to use numeric data types to perform operations, and use Format only when you need to make these numeric values "pretty" for display. Avoid making arithmetic operations on strings: while that may work, it also may fail, depending on how the string is formatted, and the system locale: VBA needs to make implicit type conversions to carry out such operations, and implicit conversions need to make a number of (sometimes wrong) assumptions.
When writing numeric values to worksheet cells, write the numeric values, not a string representation of them (same for dates. especially dates, actually). Instead of Format-ing the values, specify a format string for Range.NumberFormat in the cells that need to be formatted. That way Excel will still understand the numeric values as such, and can still correctly perform e.g. SUM operations.
The code is working exactly as specified and intended.

Basic VBA Questions (Integer)

Sub CommandButton1_Click()
Dim x As Integer
x = 6
Range("A1").Value = x
End Sub
This means that you assign X as Integer, and you say the x equals to 6.
And then you put the value x(=6) in cell "A1".
Sub CommandButton1_Click()
Dim x As Double
x = 6
Range("A1").Value = x
End Sub
But why does the second one work also?
TL;DR: Type conversions.
Range.Value is a Variant, which is a special data type that stores a pointer to a value, along with a description of the data type: that's how a cell can hold a Double, a String, a Boolean, or an Error value.
Anything deeper than that is irrelevant to the question at hand.
Integer is a 16-bit signed integer type that can easily fit into a Double, which is much larger than 16 bits. If you followed the .Value assignment with this:
Debug.Print TypeName(Range("A1").Value)
You would get Double in the debug output.
Somewhere in the implementation of the Range.Value property, a validation of the supplied value is performed, and if the value is acceptable, it's stored internally in the appropriate data type. If the value isn't of an acceptable data type, error 1004 is thrown. Integer being a fine numeric value, all is good.
The exact same thing happens in the second snippet: Double being a fine numeric value, all is good. And since any numeric value taken from a cell is a Variant/Double, we can reasonably infer that somewhere in the internal guts of Range, numeric values are stored as Double - although, that could very well just be an implementation detail of how the getter of the Range.Value property is implemented.
VBA was designed to work with a specific set of data types, and the type libraries of VBA host applications (e.g. Excel) were designed to accept these data types. Hence, you would have to work pretty hard to give Range.Value a value it can't deal with, using VBA code.
But before the value even gets to the Range.Value property, an implicit type conversion has aready occurred in the second snippet.
Dim x As Integer
x = 6
Here 6 is an integer literal. When VBA executes the x = 6 instruction, that 6 already has a data type - and that data type is Integer.
Dim x As Double
x = 6
Here 6 is also an integer literal, but it's assigned to a Double, which isn't the same type: an implicit type conversion occurs, and x happily takes an Integer value - because the conversion is widening.
Now consider:
Dim x As Double
x = 6#
Here 6# uses a type hint. Debug.Print TypeName(6#) prints Double: that 6# is a Double literal - no type conversion occurs here. But it's ugly.
Dim x As Double
x = CDbl(6)
Now the widening type conversion is explicit.
When an implicit conversion is narrowing instead, and the value can't fit into the needed data type...
Dim x As Integer
x = 32768 '<~ that's a Long integer literal: doesn't fit the 16 bits of an Integer
...then runtime error 6 ("Overflow") is thrown. Since every VBA numeric data type can safely be converted to a Double, every numeric value that can be supplied by VBA code, can be assigned to Range.Value.
Internally Excel does not use an Integer. Cells are one of four types:
Double precision floating point (all numbers including integers,
currency, dates times etc)
String
Boolean
Error
Note this means all numbers are doubles.
See these references:
Data types used by Excel - "All worksheet numbers in Excel are stored as doubles"
Excel VBA internal data format and memory storage

By creating a Variable that is defined as a string with a fixed-length, is the used bytes per cell or range?

as a relatively new user to Excel, I could not seem to find any confirmation if the a string with a fixed-length has the memory assigned per range or cell.
I am thinking it is per range, because I could not create a string with a fixed-length and set the range as the last cell in a row.
Ex:
Dim HilvlActivity as String * 3
HilvlActivitySource = Range("F3", "F:F").End(xlDown).Row
And instead, had to use
Dim HilvlActivity as String * 5000
HilvlActivitySource = Range("F3", "F:F").End(xlDown).Row
So my question is basically: is the assigned fixed-length definition per cell (Ex: F3) or per the entire assigned range?
I may be overthinking this, or should have coded the end of the row more efficiently (will change later). But this is still a basic concept that I want to make sure I understand. Some of the information I have looked into is John Walkenbach's book for Power Programming with VBA, Microsoft (https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/data-types/string-data-type), PowerSpreadSheets (https://powerspreadsheets.com/vba-data-types/#Long-VBA-Data-Type), but still can't seem to find the correct answer.
Anyone know of any good resources that really dives into variable details, it would be appreciate. Otherwise, thanks for the help! :)
Well, first: You haven't defined HilvlActivitySource as a variable anywhere...
The length of a fixed-length-string is applied to the string variable itself. For example:
Dim HilvlActivity as String * 3
HilvlActivity = ActiveSheet.Range("F3").Value
MsgBox Len(HilvlActivity)
will always show the message 3 - if F3 contains less than 3 characters, then there will be spaces added to the end. If F3 contains more than 3 characters, then only the first 3 will be stored.
Dim a as String * 10 means that the string a will be always of length 10 and if an assigned value goes above this length it will be cut to the first 10 chars.
This illustrates it:
Public Sub TestMe()
Dim a As String * 3
Dim b As String
Dim c As String * 10
a = "ABCD"
b = "ABCD"
c = "ABCD"
Debug.Print a 'ABC
Debug.Print b 'ABCD
Debug.Print Len(c) '10
Range("A1") = StrReverse(c) ' DCBA in range "A1" with 6 empty spaces upfront
End Sub

VB.Net: Writing To Excel Workbook as Text

I have written the following function...
Public Function writeAUTLSheet(doc As XDocument, myNameSpaces As Dictionary(Of String, XNamespace), theSheet As Excel.Worksheet)
'Grab the number of the last row to not overwrite
Dim rowNumber As Integer = getLastRow(theSheet)
For Each myName As XElement In doc.Descendants.Elements(myNameSpaces("ns4") + "autl")
theSheet.Cells(rowNumber, 1) = doc.Descendants.Elements(myNameSpaces("ns") + "number").Value
theSheet.Cells(rowNumber, 2) = myName.Descendants(myNameSpaces("ns") + "id").Value
theSheet.Cells(rowNumber, 3) = myName.Descendants(myNameSpaces("ns") + "name").Value
rowNumber = rowNumber + 1
Next
End Function
It runs as expected, but some values are written as "General" and others are written as "Date". This leads to values such as 07-2-3018 being turned into 7/2/3018. Then if I change that cell to "Text" or "General"(manually) it turns into "408525".
Is there a way to specify that I want it to be written as text to achieve 07-2-3-18 being written?
When you put data that might be a string, or might be a date, Excel does wacky things with it, as you've observed, because it has no way of knowing whether the data you've provided should be one type or another.
Usually, anything that can be interpreted as a Date type, is interpreted as such. So, 1/1/2017 would be a valid date but 13/47/5047 cannot be, so Excel will treat the latter as a string literal, the former as a Date type. If a value is considered a Date, then it is also a Long numeric. The 408525 value is the long numeric representation of the Date value 7/2/3018.
There should be a NumberFormat property of your Cells object (which is an Excel.Range type), but the NumberFormat doesn't change the underlying value, and it's the interpretation of the value which is confusing Excel and causing it to represent date-like values as Dates.
You can always prepend the cell value with an apostrophe, which will force Excel to interpret as string, e.g.:
theSheet.Cells(rowNumber, 2) = "'" + myName.Descendants(myNameSpaces("ns") + "id").Value

Conversion from hexadecimal string to Double yields wrong results

I am trying to convert 14 bit hex numbers to decimal.
I have this VBA code.
Option Explicit
Public Function HexadecimalToDecimal(HexValue As String) As Double
Dim ModifiedHexValue As String
ModifiedHexValue = Replace(HexValue, "0x", "&H")
HexadecimalToDecimal = CDec(ModifiedHexValue)
End Function
With numbers like this to convert to decimal
0x047B1142591E80
0x044A81325A1E80
0x047B7542591E80
I keep getting random results across large amounts of data. Sometimes spot on other times the numbers are off by 6 or 2.
Try changing the return type of the function from Double to Variant. Double has only about 15 decimal digits of precision, so can't, for example, capture the value 1261213964639872 (which has 16 digits) exactly. The closest it can get is 1261213964639870. By changing the return type to Variant, the full precision returned by CDec will be preserved. You can't use a Decimal return type, because VBA for some reason does not support this.
The problem isn't with VBA. Excel cells can only hold 15 digits in number format. So the "number" 1234567891234567 will always display 1234567891234560. This can be avoided by converting items to text AND/OR changing the cell format to text.
But this doesn't always work.
The only surefire way to make sure it will retain all digits is to append something onto the string that isn't a number.
This code will append an apostrophe before the number, but return the entire string.
Public Function HexadecimalToDecimal(HexValue As String) As String
Dim ModifiedHexValue As String
ModifiedHexValue = Replace(HexValue, "0x", "&H")
HexadecimalToDecimal = "'" & CDec(ModifiedHexValue)
End Function
Unfortunately, not a perfect solution.

Resources