Paul Kelly's Blog, page 2

July 13, 2015

The Ultimate Guide to VBA String Functions













String operationsFunction(s)




Append two or more stringsFormat or "&"


Build a string from an arrayJoin


Compare - normalStrComp or "="


Compare - patternLike


Convert to a stringCStr, Str


Convert string to dateSimple: CDate

Advanced: Format


Convert string to numberSimple: CLng, CInt, CDbl, Val

Advanced: Format


Convert to unicode, wide, narrowStrConv


Convert to upper/lower caseStrConv, UCase, LCase


Extract part of a stringLeft, Right, Mid


Format a stringFormat


Find characters in a stringInStr, InStrRev


Generate a stringString


Get length of a stringLen


Remove blanksLTrim, RTrim, Trim


Replace part of a stringReplace


Reverse a stringStrReverse


Parse string to array Split




Introduction

Using strings is a very important part of VBA. There are many types of manipulation you may wish to do with strings. These include tasks such as



extracting part of a string
comparing strings
converting numbers to a string
formatting a date to include weekday
finding a character in a string
removing blanks
parsing to an array
and so on

The good news is that VBA contains plenty of functions to help you perform these tasks with ease.


This post provides an in-depth guide to using string in VBA. It explains strings in simple terms with clear code examples. I have laid it out so the post can be easily used as a quick reference guide.


If you are going to use strings a lot then I recommend you read the first section as it applies to a lot of the functions. Otherwise you can read in order or just go to the section you require.


VBA Strings

© Ra2studio | Dreamstime.com


 


Read This First!

The following two points are very important when dealing with VBA string functions.


The Original String is not Changed

An important point to remember is that the VBA string functions do not change the original string. They return a new string with the changes the function made. If you want to change the original string you simply assign the result to the original string. See the section Extracting Part of a String for examples of this.


How To Use Compare

Some of the string functions such as StrComp() and Instr() etc. have an optional Compare parameter. This works as follows:


vbTextCompare: Upper and lower case are considered the same


vbBinaryCompare: Upper and lower case are considered different


The following code uses the string comparison function StrComp() to demonstrate the Compare parameter



Sub Comp1()

' Prints 0 : Strings match
Debug.Print StrComp("ABC", "abc", vbTextCompare)
' Prints -1 : Strings do not match
Debug.Print StrComp("ABC", "abc", vbBinaryCompare)

End Sub

You can use the Option Compare setting instead of having to use this parameter each time. Option Compare is set at the top of a Module. Any function that uses the Compare parameter will take this setting as the default. The two ways to use Option Compare are:


1. Option Compare Text: makes vbTextCompare the default Compare argument



Option Compare Text

Sub Comp2()
' Strings match - uses vbCompareText as Compare argument
Debug.Print StrComp("ABC", "abc")
Debug.Print StrComp("DEF", "def")
End Sub

2. Option Compare Binary: Makes vbBinaryCompare the default Compare argument



Option Compare Binary

Sub Comp2()
' Strings do not match - uses vbCompareBinary as Compare argument
Debug.Print StrComp("ABC", "abc")
Debug.Print StrComp("DEF", "def")
End Sub

If Option Compare is not used then the default is  Option Compare Binary.


Now that you understand these two important points about string we can go ahead and look at the string functions individually.


Go back to menu


Appending Strings
VBA String Functions - Smaller

ABC Cube Pile © Aleksandr Atkishkin | Dreamstime.com


You can append strings using the & operator. The following code shows some examples of using it



Sub Append()

Debug.Print "ABC" & "DEF"
Debug.Print "Jane" & " " & "Smith"
Debug.Print "Long " & 22
Debug.Print "Double " & 14.99
Debug.Print "Date " & #12/12/2015#

End Sub

You can see in the example that different types such as dates and number are automatically converted to strings. You may see the operator being used to append strings. The difference is that this operator will only work with string types. If you try to use it with other type you will get an error.



' This will give the error message: "Type Mismatch"
Debug.Print "Long " 22

If you want to do more complex appending of strings then you may wish to use the Format function described below.


Go back to menu


Extracting Part of a String

The functions discussed in this section are useful when dealing with basic extracting from a string. For anything more complicated you might want to check out my post on How to Easily Extract From Any String Without Using VBA InStr.






FunctionParamsDescriptionExample




Leftstring, lengthReturn chars from left sideLeft("John Smith",4)


Rightstring, lengthReturn chars from right sideRight("John Smith",5)


Midstring, start, lengthReturn chars from middleMid("John Smith",3,2)




The Left, Right, and Mid functions are used to extract parts of a string. They are very simple functions to use. Left reads characters from the left, Right from the right and Mid from a starting point that you specify.



Sub UseLeftRightMid()

Dim sCustomer As String
sCustomer = "John Thomas Smith"

Debug.Print Left(sCustomer, 4) ' Prints: John
Debug.Print Right(sCustomer, 5) ' Prints: Smith

Debug.Print Left(sCustomer, 11) ' Prints: John Thomas
Debug.Print Right(sCustomer, 12) ' Prints: Thomas Smith

Debug.Print Mid(sCustomer, 1, 4) ' Prints: John
Debug.Print Mid(sCustomer, 6, 6) ' Prints: Thomas
Debug.Print Mid(sCustomer, 13, 5) ' Prints: Smith

End Sub

As mentioned in the previous section, VBA string functions do not change the original string. Instead, they return the result as a new string.


In the next example you can see that the string Fullname was not changed after using the Left function



Sub UsingLeftExample()

Dim Fullname As String
Fullname = "John Smith"

Debug.Print "Firstname is: "; Left(Fullname, 4)
' Original string has not changed
Debug.Print "Fullname is: "; Fullname

End Sub

If you want to change the original string you simply assign it to the return value of the function



Sub ChangingString()

Dim name As String
name = "John Smith"

' Assign return string to the name variable
name = Left(name, 4)

Debug.Print "Name is: "; name

End Sub

Go back to menu


Searching Within a String




FunctionParamsDescriptionExample




InStrString1, String2Finds position of stringInStr("John Smith","h")


InStrRevStringCheck, StringMatchFinds position of string from endInStrRev("John Smith","h")




InStr and InStrRev are VBA functions used to search through strings for a substring. If the search string is found then the position(from the start of the check string) of the search string is returned. If the search string is not found then zero is returned. If either string is null then null is returned.


InStr Description of Parameters 

InStr() Start[Optional], String1, String2, Compare[Optional]



Start As Long[Optional – Default is 1]: This is a number that specifies the starting search position from the left
String1 As String: The string to search
String2 As String: The string to search for
Compare As vbCompareMethod : See the section on Compare above for more details

 


InStr Use and Examples

InStr returns the first position in a string where a given substring is found. The following shows some examples of using it



Sub FindSubString()

Dim name As String
name = "John Smith"

' Returns 3 - position of first h
Debug.Print InStr(name, "h")
' Returns 10 - position of first h starting from position 4
Debug.Print InStr(4, name, "h")
' Returns 8
Debug.Print InStr(name, "it")
' Returns 6
Debug.Print InStr(name, "Smith")
' Returns 0 - string "SSS" not found
Debug.Print InStr(name, "SSS")

End Sub

 


InStrRev Description of Parameters 

InStrRev() StringCheck, StringMatch, Start[Optional], Compare[Optional]



StringCheck As String: The string to search
StringMatch: The string to search for
Start As Long[Optional – Default is -1]: This is a number that specifies the starting search position from the right
Compare As vbCompareMethod: See the section on Compare above for more details

 


InStrRev Use and Examples

The InStrRev function is the same as InStr except that it searches from the end of the string. It’s important to note that the position returned is the position from the start. Therefore if there is only one instance of the search item then both InStr() and InStrRev() will return the same value.


The following code show some examples of using InStrRev



Sub UsingInstrRev()

Dim name As String
name = "John Smith"

' Both Return 1 - position of the only J
Debug.Print InStr(name, "J")
Debug.Print InStrRev(name, "J")

' Returns 10 - second h
Debug.Print InStrRev(name, "h")
' Returns 3 - first h as searches from position 9
Debug.Print InStrRev(name, "h", 9)

' Returns 1
Debug.Print InStrRev(name, "John")

End Sub

The InStr and InStrRev functions are useful when dealing with basic string searches. However, if you are going to use them for extracting text from a string they can make things complicated. I have written about a much better way to do this in my post How to Easily Extract From Any String Without Using VBA InStr.


 


Go back to menu


Removing Blanks





FunctionParamsDescriptionExample




LTrimstringRemoves spaces from leftLTrim(" John ")


RTrimstringRemoves spaces from rightRTrim(" John ")


TrimstringRemoves Spaces from left and rightTrim(" John ")





The Trim functions are simple functions that remove spaces from either the start or end of a string.


Trim Functions Use and Examples

LTrim removes spaces from the left of a string
RTrim removes spaces from the right of a string
Trim removes spaces from the left and right of a string


Sub TrimStr()

Dim name As String
name = " John Smith "

' Prints "John Smith "
Debug.Print LTrim(name)
' Prints " John Smith"
Debug.Print RTrim(name)
' Prints "John Smith"
Debug.Print Trim(name)

End Sub

Go back to menu


Length of a String





FunctionParamsDescriptionExample




LenstringReturns length of stringLen ("John Smith")





Len is a simple function when used with a string. It simply returns the number of characters the string contains. If used with a numeric type such as long it will return the number of bytes.



Sub GetLen()

Dim name As String
name = "John Smith"

' Prints 10
Debug.Print Len("John Smith")
' Prints 3
Debug.Print Len("ABC")

' Prints 4 as Long is 4 bytes in size
Dim total As Long
Debug.Print Len(total)

End Sub

Go back to menu


Reversing a String





FunctionParamsDescriptionExample




StrReversestringReverses a stringStrReverse ("John Smith")





StrReverse is another easy-to-use function. It simply returns the given string with the characters reversed.



Sub RevStr()

Dim s As String
s = "Jane Smith"
' Prints: htimS enaJ
Debug.Print StrReverse(s)

End Sub

Go back to menu


Comparing Strings





FunctionParamsDescriptionExample




StrCompstring1, string2Compares 2 stringsStrComp ("John", "John")





The function StrComp is used to compare two strings. The following subsections describe how it is used.


Description of Parameters 

StrComp()  String1, String2, Compare[Optional]



String1 As String: The first string to compare
String2 As String: The second string to compare
Compare As vbCompareMethod : See the section on Compare above for more details

 


StrComp Return Values




Return ValueDescription




0Strings match


-1string1 less than string2


1string1 greater than string2


Nullif either string is null




Use and Examples

The following are some examples of using the StrComp function



Sub UsingStrComp()

' Returns 0
Debug.Print StrComp("ABC", "ABC", vbTextCompare)
' Returns 1
Debug.Print StrComp("ABCD", "ABC", vbTextCompare)
' Returns -1
Debug.Print StrComp("ABC", "ABCD", vbTextCompare)
' Returns Null
Debug.Print StrComp(Null, "ABCD", vbTextCompare)

End Sub

 


Compare Strings using Operators

You can also use the equals sign to compare strings. The difference between the equals comparison and the StrComp function are:



The equals sign returns only true or false.
You cannot specify a Compare parameter using the equal sign – it uses the “Option Compare” setting.

The following shows some examples of using equals to compare strings



Option Compare Text

Sub CompareUsingEquals()

' Returns true
Debug.Print "ABC" = "ABC"
' Returns true because "Compare Text" is set above
Debug.Print "ABC" = "abc"
' Returns false
Debug.Print "ABCD" = "ABC"
' Returns false
Debug.Print "ABC" = "ABCD"
' Returns null
Debug.Print Null = "ABCD"

End Sub

The Operator “<>” means “does not equal”. It is essentially the opposite of using the equals sign as the following code shows



Option Compare Text

Sub CompareWithNotEqual()

' Returns false
Debug.Print "ABC" <> "ABC"
' Returns true because "Compare Text" is set above
Debug.Print "ABC" <> "abc"
' Returns true
Debug.Print "ABCD" <> "ABC"
' Returns true
Debug.Print "ABC" <> "ABCD"
' Returns null
Debug.Print Null <> "ABCD"

End Sub

Go back to menu


Comparing Strings using Pattern Matching




OperatorParamsDescriptionExample




Likestring, string patternchecks if string has the given pattern"abX" Like "??X"

"54abc5" Like "*abc#"








TokenMeaning




?Any single char


#Any single digit(0-9)


*zero or more characters


[charlist]Any char in the list


[!charlist]Any char not in the char list




Pattern matching is used to determine if a string has a particular pattern of characters. For example, you may want to check that a customer number has 3 digits followed by 3 alphabetic characters or a string has the letters XX followed by any number of characters.


If the string matches the pattern then the return value is true, otherwise it is false.


Pattern matching is similar to the VBA Format function in that there are almost infinite ways to use it. In this section I am going to give some examples that will explain how it works. This should cover the most common uses. If you need more information about pattern matching you can refer to the MSDN Page for the Like operator.


Lets have a look at a basic example using the tokens. Take the following pattern string


[abc][!def]?#X*


Let’s look at how this string works

[abc] a character that is either a,b or c

[!def] a character that is not d,e or f

? any character

# any digit

X the character X

* followed by zero or more characters


Therefore the following string is valid

apY6X


a is one of abc

p is not one of the characters d, e or f

Y is any character

6 is a digit

X is the letter X


The following code examples show the results of various strings with this pattern



Sub Patterns()

' True
Debug.Print 1; "apY6X" Like "[abc][!def]?#X*"
' True - any combination of chars after x is valid
Debug.Print 2; "apY6Xsf34FAD" Like "[abc][!def]?#X*"
' False - char d not in [abc]
Debug.Print 3; "dpY6X" Like "[abc][!def]?#X*"
' False - 2nd char e is in [def]
Debug.Print 4; "aeY6X" Like "[abc][!def]?#X*"
' False - A at position 4 is not a digit
Debug.Print 5; "apYAX" Like "[abc][!def]?#X*"
' False - char at position 5 must be X
Debug.Print 1; "apY6Z" Like "[abc][!def]?#X*"

End Sub

 


Real-World Example of Pattern Matching

To see a real-world example of using pattern matching check out .


Important Note on VBA Pattern Matching

The Like operator uses either Binary or Text comparison based on the Option Compare setting. Please see the section on Compare above for more details.


Go back to menu


Replace Part of a String





FunctionParamsDescriptionExample




Replacestring, find, replace,
start, count, compareReplaces a substring with a substringReplace ("Jon","n","hn")





Replace is used to replace a substring in a string by another substring. It replaces all instances of the substring that are found by default.


Replace Description of Parameters 

Replace()  Expression, Find, Replace, Start[Optional], Count[Optional], Compare[Optional]



Expression As String: The string to replace chars in
Find As String: The substring to replace in the Expression string
Replace As String: The string to replace the Find substring with
Start As Long[Optional – Default is 1]: The start position in the string
Count  As Long[Optional – Default is -1]: The number of substitutions to make. The default -1 means all.
Compare As vbCompareMethod : See the section on Compare above for more details


Use and Examples

The following code shows some examples of using the Replace function



Sub ReplaceExamples()

' Replaces all the question marks with(?) with semi colons(;)
Debug.Print Replace("A?B?C?D?E", "?", ";")
' Replace Smith with Jones
Debug.Print Replace("Peter Smith,Ann Smith", "Smith", "Jones")
' Replace AX with AB
Debug.Print Replace("ACD AXC BAX", "AX", "AB")

End Sub

Output

A;B;C;D;E

Peter Jones,Sophia Jones

ACD ABC BAB


In the following examples we use the Count optional parameter. Count determines the number of substitutions to make. So for example, setting Count equal to one means that only the first occurrence will be replaced.



Sub ReplaceCount()

' Replaces first question mark only
Debug.Print Replace("A?B?C?D?E", "?", ";", Count:=1)
' Replaces first three question marks
Debug.Print Replace("A?B?C?D?E", "?", ";", Count:=3)

End Sub

Output

A;B?C?D?E

A;B;C;D?E


The Start optional parameter allow you to return part of a string. The position you specify using Start is where it starts returning the string from. It will not return any part of the string before this position whether a replace was made or not.



Sub ReplacePartial()

' Use original string from position 4
Debug.Print Replace("A?B?C?D?E", "?", ";", Start:=4)
' Use original string from position 8
Debug.Print Replace("AA?B?C?D?E", "?", ";", Start:=8)
' No item replaced but still only returns last 2 characters
Debug.Print Replace("ABCD", "X", "Y", Start:=3)

End Sub

Output

;C;D;E

;E

CD


Sometimes you may only want to replace only upper or lower case letters. You can use the Compare parameter to do this. This is used in a lot of string functions.  For more information on this check out the Compare section above.



Sub ReplaceCase()

' Replace capital A's only
Debug.Print Replace("AaAa", "A", "X", Compare:=vbBinaryCompare)
' Replace All A's
Debug.Print Replace("AaAa", "A", "X", Compare:=vbTextCompare)

End Sub

Output

XaXa

XXXX


Multiple Replaces

If you want to replace multiple values in a string you can nest the calls. In the following code we want to replace X and Y with A and B respectively.



Sub ReplaceMulti()

Dim newString As String

' Replace A with X
newString = Replace("ABCD ABDN", "A", "X")
' Now replace B with Y in new string
newString = Replace(newString, "B", "Y")

Debug.Print newString

End Sub

In the next example we will change the above code to perform the same task. We will use the return value of the first replace as the argument for the second replace.



Sub ReplaceMultiNested()

Dim newString As String

' Replace A with X and B with Y
newString = Replace(Replace("ABCD ABDN", "A", "X"), "B", "Y")

Debug.Print newString

End Sub

The result of both of these Subs is

XYCD XYDN


Go back to menu


Convert Types to String(Basic)

This section is about converting numbers to a string. A very important point here is that most the time VBA will automatically convert to a string for you. Let’s look at some examples



Sub AutoConverts()

Dim s As String
' Automatically converts number to string
s = 12.99
Debug.Print s

' Automatically converts multiple numbers to string
s = "ABC" & 6 & 12.99
Debug.Print s

' Automatically converts double variable to string
Dim d As Double, l As Long
d = 19.99
l = 55
s = "Values are " & d & " " & l
Debug.Print s

End Sub

When you run the above code you can see that the number were automatically converted to strings. So when you assign a value to a string VBA will look after the conversion for you most of the time. There are conversion functions in VBA and in the following sub sections we will look at the reasons for using them.


Explicit Conversion




FunctionParamsDescriptionExample




CStrexpressionConverts a number variable to a stringCStr ("45.78")


StrnumberConverts a number variable to a stringStr ("45.78")




In certain cases you may want to convert an item to a string without have to place it in a string variable first. In this case you can use the Str or CStr functions. Both take an  expression as a function and this can be any type such as long, double, data or boolean.


Let’s look at a simple example. Imagine you are reading a list of values from different types of cells to a collection. You can use the Str/CStr functions to ensure they are all stored as strings. The following code shows an example of this



Sub UseStr()

Dim coll As New Collection
Dim c As Range

' Read cell values to collection
For Each c In Range("A1:A10")
' Use Str to convert cell value to a string
coll.Add Str(c)
Next

' Print out the collection values and type
Dim i As Variant
For Each i In coll
Debug.Print i, TypeName(i)
Next

End Sub

In the above example we use Str to convert the value of the cell to a string. The alternative to this would be to assign the value to a string and then assigning the string to the collection. So you can see that using Str here is much more efficient.


Multi Region

The difference between the Str and CStr functions is that CStr converts based on the region. If your macros will be used in multiple regions then you will need to use CStr for you string conversions.


It is good practise to use CStr when reading values from cells. If your code ends up being used in another region then you will not have to make any changes to make it work correctly.


Go back to menu


Convert String to Number- CLng, CDbl, Val etc.





FunctionReturnsExample




CBoolBooleanCBool("True"), CBool("0")


CCurCurrencyCCur("245.567")


CDateDateCDate("1/1/2017")


CDblDoubleCCur("245.567")


CDecDecimalCDec("245.567")


CIntIntegerCInt("45")


CLngLong IntegerCLng("45.78")


CVarVariantCVar("")





The above functions are used to convert strings to various types. If you are assigning to a variable of this type then VBA will do the conversion automatically.



Sub StrToNumeric()

Dim l As Long, d As Double, c As Currency
Dim s As String
s = "45.923239"

l = s
d = s
c = s

Debug.Print "Long is "; l
Debug.Print "Double is "; d
Debug.Print "Currency is "; c

End Sub

Using the conversion types gives more flexibility. It means you can determine the type at runtime. In the following code we set the type based on the sType argument passed to the PrintValue function. As this type can be read from an external source such as a cell, we can set the type at runtime. If we declare a variable as Long then it will always be long when the code runs.




Sub Test()
' Prints 46
PrintValue "45.56", "Long"
' Print 45.56
PrintValue "45.56", ""
End Sub

Sub PrintValue(ByVal s As String, ByVal sType As String)

Dim value

' Set the data type based on a type string
If sType = "Long" Then
value = CLng(s)
Else
value = CDbl(s)
End If
Debug.Print "Type is "; TypeName(value); value

End Sub

If a string is not a valid number(i.e. contains symbols other numeric) then you get a “Type Mismatch” error.



Sub InvalidNumber()

Dim l As Long

' Will give type mismatch error
l = CLng("45A")

End Sub

 


The Val Function

The value function convert numeric parts of a string to the correct number type.


The Val function converts the first numbers it meets. Once it meets letters in a string it stops. If there are only letters then it returns zero as the value. The following code shows some examples of using Val



Sub UseVal()

' Prints 45
Debug.Print Val("45 New Street")

' Prints 45
Debug.Print Val(" 45 New Street")

' Prints 0
Debug.Print Val("New Street 45")

' Prints 12
Debug.Print Val("12 f 34")

End Sub

The Val function has two disadvantages


1. Not Multi-Region – Val does not recognise international versions of numbers such as using commas instead of decimals. Therefore you should use the above conversion functions when you application will be used in multiple regions.


2. Converts invalid strings to zero – This may be okay in some instances but in most cases it is better if an invalid string raises an error. The application is then aware there is a problem and can act accordingly. The conversion functions such as CLng will raise an error if the string contains non-numeric characters.


Go back to menu


Generate a String of items – String Function





FunctionParamsDescriptionExample




Stringnumber, characterConverts a number variable to a stringString (5,"*")





The String function is used to generate a string of repeated characters. The first argument is the number of times to repeat it, the second argument is the character.



Sub GenString()

' Prints: AAAAA
Debug.Print String(5, "A")
' Prints: >>>>>
Debug.Print String(5, 62)
' Prints: (((ABC)))
Debug.Print String(3, "(") & "ABC" & String(3, ")")

End Sub

Go back to menu


Convert Case/Unicode – StrConv, UCase, LCase





FunctionParamsDescriptionExample




StrConvstring, conversion, LCIDConverts a StringStrConv("abc",vbUpperCase)





If you want to convert the case of a string to upper or lower you can use the UCase and LCase functions for upper and lower respectively. You can also use the StrConv function with the vbUpperCase or vbLowerCase argument. The following code shows example of using these three functions



Sub ConvCase()

Dim s As String
s = "Mary had a little lamb"

' Upper
Debug.Print UCase(s)
Debug.Print StrConv(s, vbUpperCase)

' Lower
Debug.Print LCase(s)
Debug.Print StrConv(s, vbLowerCase)

' Sets the first letter of each word to upper case
Debug.Print StrConv(s, vbProperCase)

End Sub

Output

MARY HAD A LITTLE LAMB

MARY HAD A LITTLE LAMB

mary had a little lamb

mary had a little lamb

Mary Had A Little Lamb


Other Conversions

As well as case the StrConv can perform other conversions based on the Conversion parameter. The following table shows a list of the different parameter values and what they do. For more information on StrConv check out the MSDN Page.






ConstantValueConverts




vbUpperCase1to upper case


vbLowerCase2to lower case


vbProperCase3first letter of each word to uppercase


vbWide*4from Narrow to Wide




vbNarrow*8from Wide to Narrow


vbKatakana**16from Hiragana to Katakana




vbHiragana32from Katakana to Hiragana


vbUnicode64to unicode


vbFromUnicode128from unicode




Go back to menu


Using Strings With Arrays




FunctionParamsDescriptionExample




Splitexpression, delimiter,
limit, compareParses a delimited string to an arrayarr = Split("A;B;C",";")


Joinsource array, delimiterConverts a one dimensional array to a strings = Join(Arr, ";")




String to Array using Split

You can easily parse a delimited string into an array. You simply use the Split function with the delimiter as parameter. The following code shows an example of using the Split function.



Sub StrToArr()

Dim arr() As String
' Parse string to array
arr = Split("John,Jane,Paul,Sophie", ",")

Dim name As Variant
For Each name In arr
Debug.Print name
Next

End Sub

Output

John

Jane

Paul

Sophie


If you would like to see some real world examples of using Split, you will find them in the post How to Easily Extract From Any String Without Using VBA InStr.


 


Array to String using Join

If you want to build a string from an array you can do so easily using the Join function. This is essentially a reverse of the Split function. The following code provides an example of using Join



Sub ArrToStr()

Dim Arr(0 To 3) As String
Arr(0) = "John"
Arr(1) = "Jane"
Arr(2) = "Paul"
Arr(3) = "Sophie"

' Build string from array
Dim sNames As String
sNames = Join(Arr, ",")

Debug.Print sNames

End Sub

Output

John,Jane,Paul,Sophie


Go back to menu


Formatting a String





FunctionParamsDescriptionExample




Formatexpression, format,
firstdayofweek, firstweekofyearFormats a string Format(0.5, "0.00%")





The Format function is used to format a string based on given instructions. It is mostly used to place a date or number in certain format. The examples below show the most common ways you would format a date.



Sub FormatDate()

Dim s As String
s = "31/12/2015 10:15:45"

' Prints: 31 12 15
Debug.Print Format(s, "DD MM YY")
' Prints: Thu 31 Dec 2015
Debug.Print Format(s, "DDD DD MMM YYYY")
' Prints: Thursday 31 December 2015
Debug.Print Format(s, "DDDD DD MMMM YYYY")
' Prints: 10:15
Debug.Print Format(s, "HH:MM")
' Prints: 10:15:45 AM
Debug.Print Format(s, "HH:MM:SS AM/PM")

End Sub

The following examples are some common ways of formatting numbers



Sub FormatNumbers()

' Prints: 50.00%
Debug.Print Format(0.5, "0.00%")
' Prints: 023.45
Debug.Print Format(23.45, "00#.00")
' Prints: 23,000
Debug.Print Format(23000, "##,000")
' Prints: 023,000
Debug.Print Format(23000, "0##,000")
' Prints: $23.99
Debug.Print Format(23.99, "$#0.00")

End Sub

The Format function is quite a large topic and could use up a full post on it’s own. If you want more information then the MSDN Format Page provides a lot of information.


Helpful Tip for Using Format

A quick way to figure out the formatting to use is by using the cell formatting on an Excel worksheet. For example add a number to a cell. Then  right click and format the cell the way you require. When you are happy with the format select Custom from the category listbox on the left.  When you select this you can see the format string in the type textbox(see image below). This is the string format you can use in VBA.


VBA Format Function

Format Cells Dialog


Go back to menu


Conclusion

In almost any type of programming, you will spend a great deal of time manipulating strings. This post covers the many different ways you use strings in VBA.


To get the most from use the table at the top to find the type of function you wish to use. Clicking on the left column of this function will bring you to that section.


If you are new to strings in VBA, then I suggest you check out the Read this First section before using any of the functions.


Please feel free to subscribe to my newsletter and get exclusive VBA content that you cannot find here on the blog, as well as free access to my eBook, How to Ace the 21 Most Common Questions in VBA which is full of examples you can use in your own code.

Free VBA eBook


 


 





The post The Ultimate Guide to VBA String Functions appeared first on Excel Macro Mastery.

 •  0 comments  •  flag
Share on Twitter
Published on July 13, 2015 10:33

The Ultimate Guide to the VBA String


Which string operation would you like to know more about? Click on the operation of your choice in the table below. This will bring you to that section where you will find in-depth information about the topic along with free code examples you can copy and use right now. Or if you prefer you can scroll down to see the table of contents.






String operationsFunction(s)




Append two or more stringsFormat or "&"


Build a string from an arrayJoin


Compare - normalStrComp or "="


Compare - patternLike


Convert to a stringCStr, Str


Convert string to dateSimple: CDate

Advanced: Format


Convert string to numberSimple: CLng, CInt, CDbl, Val

Advanced: Format


Convert to unicode, wide, narrowStrConv


Convert to upper/lower caseStrConv, UCase, LCase


Extract part of a stringLeft, Right, Mid


Format a stringFormat


Find characters in a stringInStr, InStrRev


Generate a stringString


Get length of a stringLen


Remove blanksLTrim, RTrim, Trim


Replace part of a stringReplace


Reverse a string

StrReverse


Parse string to array Split




Introduction

Using strings is a very important part of VBA. There are many types of manipulation you may wish to do with strings. These include tasks such as



extracting part of a string
comparing strings
converting numbers to a string
formatting a date to include weekday
finding a character in a string
removing blanks
parsing to an array
and so on

The good news is that VBA contains plenty of functions to help you perform these tasks with ease.


This post provides an in-depth guide to using string in VBA. It explains strings in simple terms with clear code examples. I have laid it out so the post can be easily used as a quick reference guide.


If you are going to use strings a lot then I recommend you read the first section as it applies to a lot of the functions. Otherwise you can read in order or just go to the section you require.


VBA Strings

© Ra2studio | Dreamstime.com


 


Read This First!

The following two points are very important when dealing with VBA string functions.


The Original String is not Changed

An important point to remember is that the VBA string functions do not change the original string. They return a new string with the changes the function made. If you want to change the original string you simply assign the result to the original string. See the section Extracting Part of a String for examples of this.


How To Use Compare

Some of the string functions such as StrComp() and Instr() etc. have an optional Compare parameter. This works as follows:


vbTextCompare: Upper and lower case are considered the same


vbBinaryCompare: Upper and lower case are considered different


The following code uses the string comparison function StrComp() to demonstrate the Compare parameter



Sub Comp1()

' Prints 0 : Strings match
Debug.Print StrComp("ABC", "abc", vbTextCompare)
' Prints -1 : Strings do not match
Debug.Print StrComp("ABC", "abc", vbBinaryCompare)

End Sub

You can use the Option Compare setting instead of having to use this parameter each time. Option Compare is set at the top of a Module. Any function that uses the Compare parameter will take this setting as the default. The two ways to use Option Compare are:


1. Option Compare Text: makes vbTextCompare the default Compare argument



Option Compare Text

Sub Comp2()
' Strings match - uses vbCompareText as Compare argument
Debug.Print StrComp("ABC", "abc")
Debug.Print StrComp("DEF", "def")
End Sub

2. Option Compare Binary: Makes vbBinaryCompare the default Compare argument



Option Compare Binary

Sub Comp2()
' Strings do not match - uses vbCompareBinary as Compare argument
Debug.Print StrComp("ABC", "abc")
Debug.Print StrComp("DEF", "def")
End Sub

If Option Compare is not used then the default is  Option Compare Binary.


Now that you understand these two important points about string we can go ahead and look at the string functions individually.


Go back to menu


Appending Strings
VBA String Functions - Smaller

ABC Cube Pile © Aleksandr Atkishkin | Dreamstime.com


You can append strings using the & operator. The following code shows some examples of using it



Sub Append()

Debug.Print "ABC" &amp;amp; "DEF"
Debug.Print "Jane" &amp;amp; " " &amp;amp; "Smith"
Debug.Print "Long " &amp;amp; 22
Debug.Print "Double " &amp;amp; 14.99
Debug.Print "Date " &amp;amp; #12/12/2015#

End Sub

You can see in the example that different types such as dates and number are automatically converted to strings. You may see the operator being used to append strings. The difference is that this operator will only work with string types. If you try to use it with other type you will get an error.



' This will give the error message: "Type Mismatch"
Debug.Print "Long " 22

If you want to do more complex appending of strings then you may wish to use the Format function described below.


Go back to menu


Extracting Part of a String




FunctionParamsDescriptionExample




Leftstring, lengthReturn chars from left sideLeft("John Smith",4)


Rightstring, lengthReturn chars from right sideRight("John Smith",5)


Midstring, start, lengthReturn chars from middleMid("John Smith",3,2)




The Left, Right, and Mid functions are used to extract parts of a string. They are very simple functions to use. Left reads characters from the left, Right from the right and Mid from a starting point that you specify.



Sub UseLeftRightMid()

Dim sCustomer As String
sCustomer = "John Thomas Smith"

Debug.Print Left(sCustomer, 4) ' Prints: John
Debug.Print Right(sCustomer, 5) ' Prints: Smith

Debug.Print Left(sCustomer, 11) ' Prints: John Thomas
Debug.Print Right(sCustomer, 12) ' Prints: Thomas Smith

Debug.Print Mid(sCustomer, 1, 4) ' Prints: John
Debug.Print Mid(sCustomer, 6, 6) ' Prints: Thomas
Debug.Print Mid(sCustomer, 13, 5) ' Prints: Smith

End Sub

As mentioned in the previous section, VBA string functions do not change the original string. Instead, they return the result as a new string.


In the next example you can see that the string Fullname was not changed after using the Left function



Sub UsingLeftExample()

Dim Fullname As String
Fullname = "John Smith"

Debug.Print "Firstname is: "; Left(Fullname, 4)
' Original string has not changed
Debug.Print "Fullname is: "; Fullname

End Sub

If you want to change the original string you simply assign it to the return value of the function



Sub ChangingString()

Dim name As String
name = "John Smith"

' Assign return string to the name variable
name = Left(name, 4)

Debug.Print "Name is: "; name

End Sub

Go back to menu


Searching Within a String




FunctionParamsDescriptionExample




InStrString1, String2Finds position of stringInStr("John Smith","h")


InStrRevStringCheck, StringMatchFinds position of string from endInStrRev("John Smith","h")




InStr and InStrRev are VBA functions used to search through strings for a substring. If the search string is found then the position(from the start of the check string) of the search string is returned. If the search string is not found then zero is returned. If either string is null then null is returned.


InStr Description of Parameters 

InStr() Start[Optional], String1, String2, Compare[Optional]



Start As Long[Optional – Default is 1]: This is a number that specifies the starting search position from the left
String1 As String: The string to search
String2 As String: The string to search for
Compare As vbCompareMethod : See the section on Compare above for more details

 


InStr Use and Examples

InStr returns the first position in a string where a given substring is found. The following shows some examples of using it



Sub FindSubString()

Dim name As String
name = "John Smith"

' Returns 3 - position of first h
Debug.Print InStr(name, "h")
' Returns 10 - position of first h starting from position 4
Debug.Print InStr(4, name, "h")
' Returns 8
Debug.Print InStr(name, "it")
' Returns 6
Debug.Print InStr(name, "Smith")
' Returns 0 - string "SSS" not found
Debug.Print InStr(name, "SSS")

End Sub

 


InStrRev Description of Parameters 

InStrRev() StringCheck, StringMatch, Start[Optional], Compare[Optional]



StringCheck As String: The string to search
StringMatch: The string to search for
Start As Long[Optional – Default is -1]: This is a number that specifies the starting search position from the right
Compare As vbCompareMethod: See the section on Compare above for more details

 


InStrRev Use and Examples

The InStrRev function is the same as InStr except that it searches from the end of the string. It’s important to note that the position returned is the position from the start. Therefore if there is only one instance of the search item then both InStr() and InStrRev() will return the same value.


The following code show some examples of using InStrRev



Sub UsingInstrRev()

Dim name As String
name = "John Smith"

' Both Return 1 - position of the only J
Debug.Print InStr(name, "J")
Debug.Print InStrRev(name, "J")

' Returns 10 - second h
Debug.Print InStrRev(name, "h")
' Returns 3 - first h as searches from position 9
Debug.Print InStrRev(name, "h", 9)

' Returns 1
Debug.Print InStrRev(name, "John")

End Sub

Go back to menu


Removing Blanks





FunctionParamsDescriptionExample




LTrimstringRemoves spaces from leftLTrim(" John ")


RTrimstringRemoves spaces from rightRTrim(" John ")


TrimstringRemoves Spaces from left and rightTrim(" John ")





The Trim functions are simple functions that remove spaces from either the start or end of a string.


Trim Functions Use and Examples

LTrim removes spaces from the left of a string
RTrim removes spaces from the right of a string
Trim removes spaces from the left and right of a string


Sub TrimStr()

Dim name As String
name = " John Smith "

' Prints "John Smith "
Debug.Print LTrim(name)
' Prints " John Smith"
Debug.Print RTrim(name)
' Prints "John Smith"
Debug.Print Trim(name)

End Sub

Go back to menu


Length of a String





FunctionParamsDescriptionExample




LenstringReturns length of stringLen ("John Smith")





Len is a simple function when used with a string. It simply returns the number of characters the string contains. If used with a numeric type such as long it will return the number of bytes.



Sub GetLen()

Dim name As String
name = "John Smith"

' Prints 10
Debug.Print Len("John Smith")
' Prints 3
Debug.Print Len("ABC")

' Prints 4 as Long is 4 bytes in size
Dim total As Long
Debug.Print Len(total)

End Sub

Go back to menu


Reversing a String





FunctionParamsDescriptionExample




StrReversestringReverses a stringStrReverse ("John Smith")





StrReverse is another easy-to-use function. It simply returns the given string with the characters reversed.



Sub RevStr()

Dim s As String
s = "Jane Smith"
' Prints: htimS enaJ
Debug.Print StrReverse(s)

End Sub

Go back to menu


Comparing Strings





FunctionParamsDescriptionExample




StrCompstring1, string2Compares 2 stringsStrComp ("John", "John")





The function StrComp is used to compare two strings. The following subsections describe how it is used.


Description of Parameters 

StrComp()  String1, String2, Compare[Optional]



String1 As String: The first string to compare
String2 As String: The second string to compare
Compare As vbCompareMethod : See the section on Compare above for more details

 


StrComp Return Values




Return ValueDescription




0Strings match


-1string1 less than string2


1string1 greater than string2


Nullif either string is null




Use and Examples

The following are some examples of using the StrComp function



Sub UsingStrComp()

' Returns 0
Debug.Print StrComp("ABC", "ABC", vbTextCompare)
' Returns 1
Debug.Print StrComp("ABCD", "ABC", vbTextCompare)
' Returns -1
Debug.Print StrComp("ABC", "ABCD", vbTextCompare)
' Returns Null
Debug.Print StrComp(Null, "ABCD", vbTextCompare)

End Sub

 


Compare Strings using Operators

You can also use the equals sign to compare strings. The difference between the equals comparison and the StrComp function are:



The equals sign returns only true or false.
You cannot specify a Compare parameter using the equal sign – it uses the “Option Compare” setting.

The following shows some examples of using equals to compare strings



Option Compare Text

Sub CompareUsingEquals()

' Returns true
Debug.Print "ABC" = "ABC"
' Returns true because "Compare Text" is set above
Debug.Print "ABC" = "abc"
' Returns false
Debug.Print "ABCD" = "ABC"
' Returns false
Debug.Print "ABC" = "ABCD"
' Returns null
Debug.Print Null = "ABCD"

End Sub

The Operator “<>” means “does not equal”. It is essentially the opposite of using the equals sign as the following code shows



Option Compare Text

Sub CompareWithNotEqual()

' Returns false
Debug.Print "ABC" &amp;lt;&amp;gt; "ABC"
' Returns true because "Compare Text" is set above
Debug.Print "ABC" &amp;lt;&amp;gt; "abc"
' Returns true
Debug.Print "ABCD" &amp;lt;&amp;gt; "ABC"
' Returns true
Debug.Print "ABC" &amp;lt;&amp;gt; "ABCD"
' Returns null
Debug.Print Null &amp;lt;&amp;gt; "ABCD"

End Sub

Go back to menu


Comparing Strings using Pattern Matching




OperatorParamsDescriptionExample




Likestring, string patternchecks if string has the given pattern"abX" Like "??X"

"54abc5" Like "*abc#"








TokenMeaning




?Any single char


#Any single digit(0-9)


*zero or more characters


[charlist]Any char in the list


[!charlist]Any char not in the char list




Pattern matching is used to determine if a string has a particular pattern of characters. For example, you may want to check that a customer number has 3 digits followed by 3 alphabetic characters or a string has the letters XX followed by any number of characters.


If the string matches the pattern then the return value is true, otherwise it is false.


Pattern matching is similar to the VBA Format function in that there are almost infinite ways to use it. In this section I am going to give some examples that will explain how it works. This should cover the most common uses. If you need more information about pattern matching you can refer to the MSDN Page for the Like operator.


Lets have a look at a basic example using the tokens. Take the following pattern string


[abc][!def]?#X*


Let’s look at how this string works

[abc] a character that is either a,b or c

[!def] a character that is not d,e or f

? any character

# any digit

X the character X

* followed by zero or more characters


Therefore the following string is valid

apY6X


a is one of abc

p is not one of the characters d, e or f

Y is any character

6 is a digit

X is the letter X


The following code examples show the results of various strings with this pattern



Sub Patterns()

' True
Debug.Print 1; "apY6X" Like "[abc][!def]?#X*"
' True - any combination of chars after x is valid
Debug.Print 2; "apY6Xsf34FAD" Like "[abc][!def]?#X*"
' False - char d not in [abc]
Debug.Print 3; "dpY6X" Like "[abc][!def]?#X*"
' False - 2nd char e is in [def]
Debug.Print 4; "aeY6X" Like "[abc][!def]?#X*"
' False - A at position 4 is not a digit
Debug.Print 5; "apYAX" Like "[abc][!def]?#X*"
' False - char at position 5 must be X
Debug.Print 1; "apY6Z" Like "[abc][!def]?#X*"

End Sub

 


Important Note on VBA Pattern Matching

The Like operator uses either Binary or Text comparison based on the Option Compare setting. Please see the section on Compare above for more details.


Go back to menu


Replace Part of a String





FunctionParamsDescriptionExample




Replacestring, find, replace,
start, count, compareReplaces a substring with a substringReplace ("Jon","n","hn")





Replace is used to replace a substring in a string by another substring. It replaces all instances of the substring that are found by default.


Replace Description of Parameters 

Replace()  Expression, Find, Replace, Start[Optional], Count[Optional], Compare[Optional]



Expression As String: The string to replace chars in
Find As String: The substring to replace in the Expression string
Replace As String: The string to replace the Find substring with
Start As Long[Optional – Default is 1]: The start position in the string
Count  As Long[Optional – Default is -1]: The number of substitutions to make. The default -1 means all.
Compare As vbCompareMethod : See the section on Compare above for more details


Use and Examples

The following code shows some examples of using the Replace function



Sub ReplaceExamples()

' Replaces all the ampersands(&amp;amp;) with semi colons(;)
Debug.Print Replace("A&amp;amp;B&amp;amp;C&amp;amp;D&amp;amp;E", "&amp;amp;", ";")
' Replace Smith with Jones
Debug.Print Replace("Peter Smith,Sophia Smith", "Smith", "Jones")
' Replace AX with AB
Debug.Print Replace("ACD AXC BAX", "AX", "AB")

End Sub

Output

A;B;C;D;E

Peter Jones,Sophia Jones

ACD ABC BAB


In the following examples we use the Count optional parameter. Count determines the number of substitutions to make. So for example, setting Count equal to one means that only the first occurrence will be replaced.



Sub ReplaceCount()

' Replaces first ampersand only
Debug.Print Replace("A&amp;amp;B&amp;amp;C&amp;amp;D&amp;amp;E", "&amp;amp;", ";", Count:=1)
' Replaces first three ampersands
Debug.Print Replace("A&amp;amp;B&amp;amp;C&amp;amp;D&amp;amp;E", "&amp;amp;", ";", Count:=3)

End Sub

Output

A;B&C&D&E

A;B;C;D&E


The Start optional parameter allow you to return part of a string. The position you specify using Start is where it starts returning the string from. It will not return any part of the string before this position whether a replace was made or not.



Sub ReplacePartial()

' Use original string from position 4
Debug.Print Replace("A&amp;amp;B&amp;amp;C&amp;amp;D&amp;amp;E", "&amp;amp;", ";", Start:=4)
' Use original string from position 8
Debug.Print Replace("A&amp;amp;B&amp;amp;C&amp;amp;D&amp;amp;E", "&amp;amp;", ";", Start:=8)
' No item replaced but still only returns last 2 characters
Debug.Print Replace("ABCD", "X", "Y", Start:=3)

End Sub

Output

;C;D;E

;E

CD


Sometimes you may only want to replace only upper or lower case letters. You can use the Compare parameter to do this. This is used in a lot of string functions.  For more information on this check out the Compare section above.



Sub ReplaceCase()

' Replace capital A's only
Debug.Print Replace("A a A a", "A", "X", Compare:=vbBinaryCompare)
' Replace All A's
Debug.Print Replace("A a A a", "A", "X", Compare:=vbTextCompare)

End Sub

Output

X a X a

X X X X


Multiple Replaces

If you want to replace multiple values in a string you can nest the calls. In the following code we want to replace X and Y with A and B respectively.



Sub ReplaceMulti()

Dim newString As String

' Replace A with X
newString = Replace("ABCD ABDN", "A", "X")
' Now replace B with Y in new string
newString = Replace(newString, "B", "Y")

Debug.Print newString

End Sub

In the next example we will change the above code to perform the same task. We will use the return value of the first replace as the argument for the second replace.



Sub ReplaceMultiNested()

Dim newString As String

' Replace A with X and B with Y
newString = Replace(Replace("ABCD ABDN", "A", "X"), "B", "Y")

Debug.Print newString

End Sub

The result of both of these Subs is

XYCD XYDN


Go back to menu


Convert Types to String(Basic)

This section is about converting numbers to a string. A very important point here is that most the time VBA will automatically convert to a string for you. Let’s look at some examples



Sub AutoConverts()

Dim s As String
' Automatically converts number to string
s = 12.99
Debug.Print s

' Automatically converts multiple numbers to string
s = "ABC" &amp;amp; 6 &amp;amp; 12.99
Debug.Print s

' Automatically converts double variable to string
Dim d As Double, l As Long
d = 19.99
l = 55
s = "Values are " &amp;amp; d &amp;amp; " " &amp;amp; l
Debug.Print s

End Sub

When you run the above code you can see that the number were automatically converted to strings. So when you assign a value to a string VBA will look after the conversion for you most of the time. There are conversion functions in VBA and in the following sub sections we will look at the reasons for using them.


Explicit Conversion




FunctionParamsDescriptionExample




CStrexpressionConverts a number variable to a stringCStr ("45.78")


StrnumberConverts a number variable to a stringStr ("45.78")




In certain cases you may want to convert an item to a string without have to place it in a string variable first. In this case you can use the Str or CStr functions. Both take an  expression as a function and this can be any type such as long, double, data or boolean.


Let’s look at a simple example. Imagine you are reading a list of values from different types of cells to a collection. You can use the Str/CStr functions to ensure they are all stored as strings. The following code shows an example of this



Sub UseStr()

Dim coll As New Collection
Dim c As Range

' Read cell values to collection
For Each c In Range("A1:A10")
' Use Str to convert cell value to a string
coll.Add Str(c)
Next

' Print out the collection values and type
Dim i As Variant
For Each i In coll
Debug.Print i, TypeName(i)
Next

End Sub

In the above example we use Str to convert the value of the cell to a string. The alternative to this would be to assign the value to a string and then assigning the string to the collection. So you can see that using Str here is much more efficient.


Multi Region

The difference between the Str and CStr functions is that CStr converts based on the region. If your macros will be used in multiple regions then you will need to use CStr for you string conversions.


It is good practise to use CStr when reading values from cells. If your code ends up being used in another region then you will not have to make any changes to make it work correctly.


Go back to menu


Convert String to Number- CLng, CDbl, Val etc.





FunctionReturnsExample




CBoolBooleanCBool("True"), CBool("0")


CCurCurrencyCCur("245.567")


CDateDateCDate("1/1/2017")


CDblDoubleCCur("245.567")


CDecDecimalCDec("245.567")


CIntIntegerCInt("45")


CLngLong IntegerCLng("45.78")


CVarVariantCVar("")





The above functions are used to convert strings to various types. If you are assigning to a variable of this type then VBA will do the conversion automatically.



Sub StrToNumeric()

Dim l As Long, d As Double, c As Currency
Dim s As String
s = "45.923239"

l = s
d = s
c = s

Debug.Print "Long is "; l
Debug.Print "Double is "; d
Debug.Print "Currency is "; c

End Sub

Using the conversion types gives more flexibility. It means you can determine the type at runtime. In the following code we set the type based on the sType argument passed to the PrintValue function. As this type can be read from an external source such as a cell, we can set the type at runtime. If we declare a variable as Long then it will always be long when the code runs.




Sub Test()
' Prints 46
PrintValue "45.56", "Long"
' Print 45.56
PrintValue "45.56", ""
End Sub

Sub PrintValue(ByVal s As String, ByVal sType As String)

Dim value

' Set the data type based on a type string
If sType = "Long" Then
value = CLng(s)
Else
value = CDbl(s)
End If
Debug.Print "Type is "; TypeName(value); value

End Sub

If a string is not a valid number(i.e. contains symbols other numeric) then you get a “Type Mismatch” error.



Sub InvalidNumber()

Dim l As Long

' Will give type mismatch error
l = CLng("45A")

End Sub

 


The Val Function

The value function convert numeric parts of a string to the correct number type.


The Val function converts the first numbers it meets. Once it meets letters in a string it stops. If there are only letters then it returns zero as the value. The following code shows some examples of using Val



Sub UseVal()

' Prints 45
Debug.Print Val("45 New Street")

' Prints 45
Debug.Print Val(" 45 New Street")

' Prints 0
Debug.Print Val("New Street 45")

' Prints 12
Debug.Print Val("12 f 34")

End Sub

The Val function has two disadvantages


1. Not Multi-Region – Val does not recognise international versions of numbers such as using commas instead of decimals. Therefore you should use the above conversion functions when you application will be used in multiple regions.


2. Converts invalid strings to zero – This may be okay in some instances but in most cases it is better if an invalid string raises an error. The application is then aware there is a problem and can act accordingly. The conversion functions such as CLng will raise an error if the string contains non-numeric characters.


Go back to menu


Generate a String of items – String Function





FunctionParamsDescriptionExample




Stringnumber, characterConverts a number variable to a stringString (5,"*")





The String function is used to generate a string of repeated characters. The first argument is the number of times to repeat it, the second argument is the character.



Sub GenString()

' Prints: &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;
Debug.Print String(5, "&amp;gt;")
' Prints: &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;
Debug.Print String(5, 62)
' Prints: (((ABC)))
Debug.Print String(3, "(") &amp;amp; "ABC" &amp;amp; String(3, ")")

End Sub

Go back to menu


Convert Case/Unicode – StrConv, UCase, LCase





FunctionParamsDescriptionExample




StrConvstring, conversion, LCIDConverts a StringStrConv("abc",vbUpperCase)





If you want to convert the case of a string to upper or lower you can use the UCase and LCase functions for upper and lower respectively. You can also use the StrConv function with the vbUpperCase or vbLowerCase argument. The following code shows example of using these three functions



Sub ConvCase()

Dim s As String
s = "Mary had a little lamb"

' Upper
Debug.Print UCase(s)
Debug.Print StrConv(s, vbUpperCase)

' Lower
Debug.Print LCase(s)
Debug.Print StrConv(s, vbLowerCase)

' Sets the first letter of each word to upper case
Debug.Print StrConv(s, vbProperCase)

End Sub

Output

MARY HAD A LITTLE LAMB

MARY HAD A LITTLE LAMB

mary had a little lamb

mary had a little lamb

Mary Had A Little Lamb


Other Conversions

As well as case the StrConv can perform other conversions based on the Conversion parameter. The following table shows a list of the different parameter values and what they do. For more information on StrConv check out the MSDN Page.






ConstantValueConverts




vbUpperCase1to upper case


vbLowerCase2to lower case


vbProperCase3first letter of each word to uppercase


vbWide*4from Narrow to Wide




vbNarrow*8from Wide to Narrow


vbKatakana**16from Hiragana to Katakana




vbHiragana32from Katakana to Hiragana


vbUnicode64to unicode


vbFromUnicode128from unicode




Go back to menu


Using Strings With Arrays




FunctionParamsDescriptionExample




Splitexpression, delimiter,
limit, compareParses a delimited string to an arrayarr = Split("A;B;C",";")


Joinsource array, delimiterConverts a one dimensional array to a strings = Join(Arr, ";")




String to Array using Split

You can easily parse a delimited string into an array. You simply use the Split function with the delimiter as parameter. The following code shows an example of using the Split function.



Sub StrToArr()

Dim arr() As String
' Parse string to array
arr = Split("John,Jane,Paul,Sophie", ",")

Dim name As Variant
For Each name In arr
Debug.Print name
Next

End Sub

Output

John

Jane

Paul

Sophie


Array to String using Join

If you want to build a string from an array you can do so easily using the Join function. This is essentially a reverse of the Split function. The following code provides an example of using Join



Sub ArrToStr()

Dim Arr(0 To 3) As String
Arr(0) = "John"
Arr(1) = "Jane"
Arr(2) = "Paul"
Arr(3) = "Sophie"

' Build string from array
Dim sNames As String
sNames = Join(Arr, ",")

Debug.Print sNames

End Sub

Output

John,Jane,Paul,Sophie


Go back to menu


Formatting a String





FunctionParamsDescriptionExample




Formatexpression, format,
firstdayofweek, firstweekofyearFormats a string Format(0.5, "0.00%")





The Format function is used to format a string based on given instructions. It is mostly used to place a date or number in certain format. The examples below show the most common ways you would format a date.



Sub FormatDate()

Dim s As String
s = "31/12/2015 10:15:45"

' Prints: 31 12 15
Debug.Print Format(s, "DD MM YY")
' Prints: Thu 31 Dec 2015
Debug.Print Format(s, "DDD DD MMM YYYY")
' Prints: Thursday 31 December 2015
Debug.Print Format(s, "DDDD DD MMMM YYYY")
' Prints: 10:15
Debug.Print Format(s, "HH:MM")
' Prints: 10:15:45 AM
Debug.Print Format(s, "HH:MM:SS AM/PM")

End Sub

The following examples are some common ways of formatting numbers



Sub FormatNumbers()

' Prints: 50.00%
Debug.Print Format(0.5, "0.00%")
' Prints: 023.45
Debug.Print Format(23.45, "00#.00")
' Prints: 23,000
Debug.Print Format(23000, "##,000")
' Prints: 023,000
Debug.Print Format(23000, "0##,000")
' Prints: $23.99
Debug.Print Format(23.99, "$#0.00")

End Sub

The Format function is quite a large topic and could use up a full post on it’s own. If you want more information then the MSDN Format Page provides a lot of information.


Helpful Tip for Using Format

A quick way to figure out the formatting to use is by using the cell formatting on an Excel worksheet. For example add a number to a cell. Then  right click and format the cell the way you require. When you are happy with the format select Custom from the category listbox on the left.  When you select this you can see the format string in the type textbox(see image below). This is the string format you can use in VBA.


VBA Format Function

Format Cells Dialog


Go back to menu


Conclusion

In almost any type of programming, you will spend a great deal of time manipulating strings. This post covers the many different ways you use strings in VBA.


To get the most from use the table at the top to find the type of function you wish to use. Clicking on the left column of this function will bring you to that section.


If you are new to strings in VBA, then I suggest you check out the Read this First section before using any of the functions.


Please feel free to subscribe to my newsletter and get exclusive VBA content that you cannot find here on the blog, as well as free access to my eBook, How to Ace the 21 Most Common Questions in VBA which is full of examples you can use in your own code.

Free VBA eBook


 


 





The post The Ultimate Guide to the VBA String appeared first on Excel Macro Mastery.

 •  0 comments  •  flag
Share on Twitter
Published on July 13, 2015 10:33

The Ultimate Guide to Using Strings in Excel VBA

“Music is the melody whose text is the world” – Arthur Schopenhauer


Quick Guide To String Functions




TaskFunction(s)




Appending stringsFormat or "&"


Array to string using JoinJoin


Compare - normalStrComp or "="


Compare - patternLike


Convert to a stringCStr, Str


Convert string to dateSimple: CDate

Advanced: Format


Convert string to numberSimple: CLng, CInt, CDbl, Val

Advanced: Format


Convert unicode, wide, narrowStrConv


Convert upper/lower caseStrConv, UCase, LCase


Extracting part of a stringLeft, Right, Mid


Format a stringFormat


Find characters in a stringInStr, InStrRev


Generate a stringString


Length of a stringLen


Remove blanksLTrim, RTrim, Trim


Replace part of a stringReplace


Reverse a string

StrReverse


String to array using SplitSplit




Introduction

Using strings is a very important part of VBA. There are many types of manipulation you may wish to do with strings. These include tasks such as



extracting part of a string
comparing strings
converting numbers to a string
formatting a date to include weekday
finding a character in a string
removing blanks
parsing to an array
and so on

The good news is that VBA contains plenty of functions to help you perform these tasks with ease.


This post provides an in-depth guide to using string in VBA. It explains strings in simple terms with clear code examples. I have laid it out so the post can be easily used as a quick reference guide.


If you are going to use strings a lot then I recommend you read the first section as it applies to a lot of the functions. Otherwise you can read in order or just go to the section you require.


VBA Strings

© Ra2studio | Dreamstime.com


 


Read This First!

The following two points are very important when dealing with VBA string functions.


The Original String is not Changed

An important point to remember is that the VBA string functions do not change the original string. They return a new string with the changes the function made. If you want to change the original string you simply assign the result to the original string. See the section Extracting Part of a String for examples of this.


How To Use Compare

Some of the string functions such as StrComp() and Instr() etc. have an optional Compare parameter. This works as follows:


vbTextCompare: Upper and lower case are considered the same


vbBinaryCompare: Upper and lower case are considered different


The following code uses the string comparison function StrComp() to demonstrate the Compare parameter



Sub Comp1()

' Prints 0 : Strings match
Debug.Print StrComp("ABC", "abc", vbTextCompare)
' Prints -1 : Strings do not match
Debug.Print StrComp("ABC", "abc", vbBinaryCompare)

End Sub

You can use the Option Compare setting instead of having to use this parameter each time. Option Compare is set at the top of a Module. Any function that uses the Compare parameter will take this setting as the default. The two ways to use Option Compare are:


1. Option Compare Text: makes vbTextCompare the default Compare argument



Option Compare Text

Sub Comp2()
' Strings match - uses vbCompareText as Compare argument
Debug.Print StrComp("ABC", "abc")
Debug.Print StrComp("DEF", "def")
End Sub

2. Option Compare Binary: Makes vbBinaryCompare the default Compare argument



Option Compare Binary

Sub Comp2()
' Strings do not match - uses vbCompareBinary as Compare argument
Debug.Print StrComp("ABC", "abc")
Debug.Print StrComp("DEF", "def")
End Sub

If Option Compare is not used then the default is  Option Compare Binary.


Now that you understand these two important points about string we can go ahead and look at the string functions individually.


Appending Strings
VBA String Functions - Smaller

ABC Cube Pile © Aleksandr Atkishkin | Dreamstime.com


You can append strings using the & operator. The following code shows some examples of using it



Sub Append()

Debug.Print "ABC" & "DEF"
Debug.Print "Jane" & " " & "Smith"
Debug.Print "Long " & 22
Debug.Print "Double " & 14.99
Debug.Print "Date " & #12/12/2015#

End Sub

You can see in the example that different types such as dates and number are automatically converted to strings. You may see the + operator being used to append strings. The difference is that this operator will only work with string types. If you try to use it with other type you will get an error.



' This will give the error message: "Type Mismatch"
Debug.Print "Long " + 22

If you want to do more complex appending of strings then you may wish to use the Format function described below.


Extracting Part of a String




FunctionParamsDescriptionExample




Leftstring, lengthReturn chars from left sideLeft("John Smith",4)


Rightstring, lengthReturn chars from right sideRight("John Smith",5)


Midstring, start, lengthReturn chars from middleMid("John Smith",3,2)




The Left, Right, and Mid functions are used to extract parts of a string. They are very simple functions to use. Left reads characters from the left, Right from the right and Mid from a starting point that you specify.



Sub UseLeftRightMid()

Dim sCustomer As String
sCustomer = "John Thomas Smith"

Debug.Print Left(sCustomer, 4) ' Prints: John
Debug.Print Right(sCustomer, 5) ' Prints: Smith

Debug.Print Left(sCustomer, 11) ' Prints: John Thomas
Debug.Print Right(sCustomer, 12) ' Prints: Thomas Smith

Debug.Print Mid(sCustomer, 1, 4) ' Prints: John
Debug.Print Mid(sCustomer, 6, 6) ' Prints: Thomas
Debug.Print Mid(sCustomer, 13, 5) ' Prints: Smith

End Sub

As mentioned in the previous section, VBA string functions do not change the original string. Instead, they return the result as a new string.


In the next example you can see that the string Fullname was not changed after using the Left function



Sub UsingLeftExample()

Dim Fullname As String
Fullname = "John Smith"

Debug.Print "Firstname is: "; Left(Fullname, 4)
' Original string has not changed
Debug.Print "Fullname is: "; Fullname

End Sub

If you want to change the original string you simply assign it to the return value of the function



Sub ChangingString()

Dim name As String
name = "John Smith"

' Assign return string to the name variable
name = Left(name, 4)

Debug.Print "Name is: "; name

End Sub

 


Searching Within a String




FunctionParamsDescriptionExample




InStrString1, String2Finds position of stringInStr("John Smith","h")


InStrRevStringCheck, StringMatchFinds position of string from endInStrRev("John Smith","h")




InStr and InStrRev are VBA functions used to search through strings for a substring. If the search string is found then the position(from the start of the check string) of the search string is returned. If the search string is not found then zero is returned. If either string is null then null is returned.


InStr Description of Parameters 

InStr() Start[Optional], String1, String2, Compare[Optional]



Start As Long[Optional – Default is 1]: This is a number that specifies the starting search position from the left
String1 As String: The string to search
String2 As String: The string to search for
Compare As vbCompareMethod : See the section on Compare above for more details

 


InStr Use and Examples

InStr returns the first position in a string where a given substring is found. The following shows some examples of using it



Sub FindSubString()

Dim name As String
name = "John Smith"

' Returns 3 - position of first h
Debug.Print InStr(name, "h")
' Returns 10 - position of first h starting from position 4
Debug.Print InStr(4, name, "h")
' Returns 8
Debug.Print InStr(name, "it")
' Returns 6
Debug.Print InStr(name, "Smith")
' Returns 0 - string "SSS" not found
Debug.Print InStr(name, "SSS")

End Sub

 


InStrRev Description of Parameters 

InStrRev() StringCheck, StringMatch, Start[Optional], Compare[Optional]



StringCheck As String: The string to search
StringMatch: The string to search for
Start As Long[Optional – Default is -1]: This is a number that specifies the starting search position from the right
Compare As vbCompareMethod: See the section on Compare above for more details

 


InStrRev Use and Examples

The InStrRev function is the same as InStr except that it searches from the end of the string. It’s important to note that the position returned is the position from the start. Therefore if there is only one instance of the search item then both InStr() and InStrRev() will return the same value.


The following code show some examples of using InStrRev



Sub UsingInstrRev()

Dim name As String
name = "John Smith"

' Both Return 1 - position of the only J
Debug.Print InStr(name, "J")
Debug.Print InStrRev(name, "J")

' Returns 10 - second h
Debug.Print InStrRev(name, "h")
' Returns 3 - first h as searches from position 9
Debug.Print InStrRev(name, "h", 9)

' Returns 1
Debug.Print InStrRev(name, "John")

End Sub

 


Removing Blanks





FunctionParamsDescriptionExample




LTrimstringRemoves spaces from leftLTrim(" John ")


RTrimstringRemoves spaces from rightRTrim(" John ")


TrimstringRemoves Spaces from left and rightTrim(" John ")





The Trim functions are simple functions that remove spaces from either the start or end of a string.


Trim Functions Use and Examples

LTrim removes spaces from the left of a string
RTrim removes spaces from the right of a string
Trim removes spaces from the left and right of a string


Sub TrimStr()

Dim name As String
name = " John Smith "

' Prints "John Smith "
Debug.Print LTrim(name)
' Prints " John Smith"
Debug.Print RTrim(name)
' Prints "John Smith"
Debug.Print Trim(name)

End Sub

 


Length of a String





FunctionParamsDescriptionExample




LenstringReturns length of stringLen ("John Smith")





Len is a simple function when used with a string. It simply returns the number of characters the string contains. If used with a numeric type such as long it will return the number of bytes.



Sub GetLen()

Dim name As String
name = "John Smith"

' Prints 10
Debug.Print Len("John Smith")
' Prints 3
Debug.Print Len("ABC")

' Prints 4 as Long is 4 bytes in size
Dim total As Long
Debug.Print Len(total)

End Sub

 


Reversing a String





FunctionParamsDescriptionExample




StrReversestringReverses a stringStrReverse ("John Smith")





StrReverse is another easy-to-use function. It simply returns the given string with the characters reversed.



Sub RevStr()

Dim s As String
s = "Jane Smith"
' Prints: htimS enaJ
Debug.Print StrReverse(s)

End Sub

 


Comparing Strings





FunctionParamsDescriptionExample




StrCompstring1, string2Compares 2 stringsStrComp ("John", "John")





The function StrComp is used to compare two strings. The following subsections describe how it is used.


Description of Parameters 

StrComp()  String1, String2, Compare[Optional]



String1 As String: The first string to compare
String2 As String: The second string to compare
Compare As vbCompareMethod : See the section on Compare above for more details

 


StrComp Return Values




Return ValueDescription




0Strings match


-1string1 less than string2


1string1 greater than string2


Nullif either string is null




Use and Examples

The following are some examples of using the StrComp function



Sub UsingStrComp()

' Returns 0
Debug.Print StrComp("ABC", "ABC", vbTextCompare)
' Returns 1
Debug.Print StrComp("ABCD", "ABC", vbTextCompare)
' Returns -1
Debug.Print StrComp("ABC", "ABCD", vbTextCompare)
' Returns Null
Debug.Print StrComp(Null, "ABCD", vbTextCompare)

End Sub

 


Compare Strings using Operators

You can also use the equals sign to compare strings. The difference between the equals comparison and the StrComp function are:



The equals sign returns only true or false.
You cannot specify a Compare parameter using the equal sign – it uses the “Option Compare” setting.

The following shows some examples of using equals to compare strings



Option Compare Text

Sub CompareUsingEquals()

' Returns true
Debug.Print "ABC" = "ABC"
' Returns true because "Compare Text" is set above
Debug.Print "ABC" = "abc"
' Returns false
Debug.Print "ABCD" = "ABC"
' Returns false
Debug.Print "ABC" = "ABCD"
' Returns null
Debug.Print Null = "ABCD"

End Sub

The Operator “<>” means “does not equal”. It is essentially the opposite of using the equals sign as the following code shows



Option Compare Text

Sub CompareWithNotEqual()

' Returns false
Debug.Print "ABC" <> "ABC"
' Returns true because "Compare Text" is set above
Debug.Print "ABC" <> "abc"
' Returns true
Debug.Print "ABCD" <> "ABC"
' Returns true
Debug.Print "ABC" <> "ABCD"
' Returns null
Debug.Print Null <> "ABCD"

End Sub

 


Comparing Strings using Pattern Matching




OperatorParamsDescriptionExample




Likestring, string patternchecks if string has the given pattern"abX" Like "??X"

"54abc5" Like "*abc#"








TokenMeaning




?Any single char


#Any single digit(0-9)


*zero or more characters


[charlist]Any char in the list


[!charlist]Any char not in the char list




Pattern matching is used to determine if a string has a particular pattern of characters. For example, you may want to check that a customer number has 3 digits followed by 3 alphabetic characters or a string has the letters XX followed by any number of characters.


If the string matches the pattern then the return value is true, otherwise it is false.


Pattern matching is similar to the VBA Format function in that there are almost infinite ways to use it. In this section I am going to give some examples that will explain how it works. This should cover the most common uses. If you need more information about pattern matching you can refer to the MSDN Page for the Like operator.


Lets have a look at a basic example using the tokens. Take the following pattern string


[abc][!def]?#X*


Let’s look at how this string works

[abc] a character that is either a,b or c

[!def] a character that is not d,e or f

? any character

# any digit

X the character X

* followed by zero or more characters


Therefore the following string is valid

apY6X


a is one of abc

p is not one of the characters d, e or f

Y is any character

6 is a digit

X is the letter X


The following code examples show the results of various strings with this pattern



Sub Patterns()

' True
Debug.Print 1; "apY6X" Like "[abc][!def]?#X*"
' True - any combination of chars after x is valid
Debug.Print 2; "apY6Xsf34FAD" Like "[abc][!def]?#X*"
' False - char d not in [abc]
Debug.Print 3; "dpY6X" Like "[abc][!def]?#X*"
' False - 2nd char e is in [def]
Debug.Print 4; "aeY6X" Like "[abc][!def]?#X*"
' False - A at position 4 is not a digit
Debug.Print 5; "apYAX" Like "[abc][!def]?#X*"
' False - char at position 5 must be X
Debug.Print 1; "apY6Z" Like "[abc][!def]?#X*"

End Sub

 


Important Note on VBA Pattern Matching

The Like operator uses either Binary or Text comparison based on the Option Compare setting. Please see the section on Compare above for more details


Replace Part of a String





FunctionParamsDescriptionExample




Replacestring, find, replace,
start, count, compareReplaces a substring with a substringReplace ("Jon","n","hn")





Replace is used to replace a substring in a string by another substring. It replaces all instances of the substring that are found by default.


Replace Description of Parameters 

Replace()  Expression, Find, Replace, Start[Optional], Count[Optional], Compare[Optional]



Expression As String: The string to replace chars in
Find As String: The substring to replace in the Expression string
Replace As String: The string to replace the Find substring with
Start As Long[Optional – Default is 1]: The start position in the string
Count  As Long[Optional – Default is -1]: The number of substitutions to make. The default -1 means all.
Compare As vbCompareMethod : See the section on Compare above for more details


Use and Examples

The following code shows some examples of using the Replace function



Sub ReplaceExamples()

' Replaces all the ampersands(&) with semi colons(;)
Debug.Print Replace("A&B&C&D&E", "&", ";")
' Replace Smith with Jones
Debug.Print Replace("Peter Smith,Sophia Smith", "Smith", "Jones")
' Replace AX with AB
Debug.Print Replace("ACD AXC BAX", "AX", "AB")

End Sub

Output

A;B;C;D;E

Peter Jones,Sophia Jones

ACD ABC BAB


In the following examples we use the Count optional parameter. Count determines the number of substitutions to make. So for example, setting Count equal to one means that only the first occurrence will be replaced.



Sub ReplaceCount()

' Replaces first ampersand only
Debug.Print Replace("A&B&C&D&E", "&", ";", Count:=1)
' Replaces first three ampersands
Debug.Print Replace("A&B&C&D&E", "&", ";", Count:=3)

End Sub

Output

A;B&C&D&E

A;B;C;D&E


The Start optional parameter allow you to return part of a string. The position you specify using Start is where it starts returning the string from. It will not return any part of the string before this position whether a replace was made or not.



Sub ReplacePartial()

' Use original string from position 4
Debug.Print Replace("A&B&C&D&E", "&", ";", Start:=4)
' Use original string from position 8
Debug.Print Replace("A&B&C&D&E", "&", ";", Start:=8)
' No item replaced but still only returns last 2 characters
Debug.Print Replace("ABCD", "X", "Y", Start:=3)

End Sub

Output

;C;D;E

;E

CD


Sometimes you may only want to replace only upper or lower case letters. You can use the Compare parameter to do this. This is used in a lot of string functions.  For more information on this check out the Compare section above.



Sub ReplaceCase()

' Replace capital A's only
Debug.Print Replace("A a A a", "A", "X", Compare:=vbBinaryCompare)
' Replace All A's
Debug.Print Replace("A a A a", "A", "X", Compare:=vbTextCompare)

End Sub

Output

X a X a

X X X X


Multiple Replaces

If you want to replace multiple values in a string you can nest the calls. In the following code we want to replace X and Y with A and B respectively.



Sub ReplaceMulti()

Dim newString As String

' Replace A with X
newString = Replace("ABCD ABDN", "A", "X")
' Now replace B with Y in new string
newString = Replace(newString, "B", "Y")

Debug.Print newString

End Sub

In the next example we will change the above code to perform the same task. We will use the return value of the first replace as the argument for the second replace.



Sub ReplaceMultiNested()

Dim newString As String

' Replace A with X and B with Y
newString = Replace(Replace("ABCD ABDN", "A", "X"), "B", "Y")

Debug.Print newString

End Sub

The result of both of these Subs is

XYCD XYDN


 


Convert Types to String(Basic)

This section is about converting numbers to a string. A very important point here is that most the time VBA will automatically convert to a string for you. Let’s look at some examples



Sub AutoConverts()

Dim s As String
' Automatically converts number to string
s = 12.99
Debug.Print s

' Automatically converts multiple numbers to string
s = "ABC" & 6 & 12.99
Debug.Print s

' Automatically converts double variable to string
Dim d As Double, l As Long
d = 19.99
l = 55
s = "Values are " & d & " " & l
Debug.Print s

End Sub

When you run the above code you can see that the number were automatically converted to strings. So when you assign a value to a string VBA will look after the conversion for you most of the time. There are conversion functions in VBA and in the following sub sections we will look at the reasons for using them.


Explicit Conversion




FunctionParamsDescriptionExample




CStrexpressionConverts a number variable to a stringCStr ("45.78")


StrnumberConverts a number variable to a stringStr ("45.78")




In certain cases you may want to convert an item to a string without have to place it in a string variable first. In this case you can use the Str or CStr functions. Both take an  expression as a function and this can be any type such as long, double, data or boolean.


Let’s look at a simple example. Imagine you are reading a list of values from different types of cells to a collection. You can use the Str/CStr functions to ensure they are all stored as strings. The following code shows an example of this



Sub UseStr()

Dim coll As New Collection
Dim c As Range

' Read cell values to collection
For Each c In Range("A1:A10")
' Use Str to convert cell value to a string
coll.Add Str(c)
Next

' Print out the collection values and type
Dim i As Variant
For Each i In coll
Debug.Print i, TypeName(i)
Next

End Sub

In the above example we use Str to convert the value of the cell to a string. The alternative to this would be to assign the value to a string and then assigning the string to the collection. So you can see that using Str here is much more efficient.


Multi Region

The difference between the Str and CStr functions is that CStr converts based on the region. If your macros will be used in multiple regions then you will need to use CStr for you string conversions.


It is good practise to use CStr when reading values from cells. If your code ends up being used in another region then you will not have to make any changes to make it work correctly.


 


Convert String to Number- CLng, CDbl, Val etc.





FunctionReturnsExample




CBoolBooleanCBool("True"), CBool("0")


CCurCurrencyCCur("245.567")


CDateDateCDate("1/1/2017")


CDblDoubleCCur("245.567")


CDecDecimalCDec("245.567")


CIntIntegerCInt("45")


CLngLong IntegerCLng("45.78")


CVarVariantCVar("")





The above functions are used to convert strings to various types. If you are assigning to a variable of this type then VBA will do the conversion automatically.



Sub StrToNumeric()

Dim l As Long, d As Double, c As Currency
Dim s As String
s = "45.923239"

l = s
d = s
c = s

Debug.Print "Long is "; l
Debug.Print "Double is "; d
Debug.Print "Currency is "; c

End Sub

Using the conversion types gives more flexibility. It means you can determine the type at runtime. In the following code we set the type based on the sType argument passed to the PrintValue function. As this type can be read from an external source such as a cell, we can set the type at runtime. If we declare a variable as Long then it will always be long when the code runs.




Sub Test()
' Prints 46
PrintValue "45.56", "Long"
' Print 45.56
PrintValue "45.56", ""
End Sub

Sub PrintValue(ByVal s As String, ByVal sType As String)

Dim value

' Set the data type based on a type string
If sType = "Long" Then
value = CLng(s)
Else
value = CDbl(s)
End If
Debug.Print "Type is "; TypeName(value); value

End Sub

If a string is not a valid number(i.e. contains symbols other numeric) then you get a “Type Mismatch” error.



Sub InvalidNumber()

Dim l As Long

' Will give type mismatch error
l = CLng("45A")

End Sub

 


The Val Function

The value function convert numeric parts of a string to the correct number type.


The Val function converts the first numbers it meets. Once it meets letters in a string it stops. If there are only letters then it returns zero as the value. The following code shows some examples of using Val



Sub UseVal()

' Prints 45
Debug.Print Val("45 New Street")

' Prints 45
Debug.Print Val(" 45 New Street")

' Prints 0
Debug.Print Val("New Street 45")

' Prints 12
Debug.Print Val("12 f 34")

End Sub

The Val function has two disadvantages


1. Not Multi-Region – Val does not recognise international versions of numbers such as using commas instead of decimals. Therefore you should use the above conversion functions when you application will be used in multiple regions.


2. Converts invalid strings to zero – This may be okay in some instances but in most cases it is better if an invalid string raises an error. The application is then aware there is a problem and can act accordingly. The conversion functions such as CLng will raise an error if the string contains non-numeric characters.


Generate a String of items – String Function





FunctionParamsDescriptionExample




Stringnumber, characterConverts a number variable to a stringString (5,"*")





The String function is used to generate a string of repeated characters. The first argument is the number of times to repeat it, the second argument is the character.



Sub GenString()

' Prints: >>>>>
Debug.Print String(5, ">")
' Prints: >>>>>
Debug.Print String(5, 62)
' Prints: (((ABC)))
Debug.Print String(3, "(") & "ABC" & String(3, ")")

End Sub

 


Convert Case/Unicode – StrConv, UCase, LCase





FunctionParamsDescriptionExample




StrConvstring, conversion, LCIDConverts a StringStrConv("abc",vbUpperCase)





If you want to convert the case of a string to upper or lower you can use the UCase and LCase functions for upper and lower respectively. You can also use the StrConv function with the vbUpperCase or vbLowerCase argument. The following code shows example of using these three functions



Sub ConvCase()

Dim s As String
s = "Mary had a little lamb"

' Upper
Debug.Print UCase(s)
Debug.Print StrConv(s, vbUpperCase)

' Lower
Debug.Print LCase(s)
Debug.Print StrConv(s, vbLowerCase)

' Sets the first letter of each word to upper case
Debug.Print StrConv(s, vbProperCase)

End Sub

Output

MARY HAD A LITTLE LAMB

MARY HAD A LITTLE LAMB

mary had a little lamb

mary had a little lamb

Mary Had A Little Lamb


Other Conversions

As well as case the StrConv can perform other conversions based on the Conversion parameter. The following table shows a list of the different parameter values and what they do. For more information on StrConv check out the MSDN Page.






ConstantValueConverts




vbUpperCase1to upper case


vbLowerCase2to lower case


vbProperCase3first letter of each word to uppercase


vbWide*4from Narrow to Wide




vbNarrow*8from Wide to Narrow


vbKatakana**16from Hiragana to Katakana




vbHiragana32from Katakana to Hiragana


vbUnicode64to unicode


vbFromUnicode128from unicode




Using Strings With Arrays




FunctionParamsDescriptionExample




Splitexpression, delimiter,
limit, compareParses a delimited string to an arrayarr = Split("A;B;C",";")


Joinsource array, delimiterConverts a one dimensional array to a strings = Join(Arr, ";")




String to Array using Split

You can easily parse a delimited string into an array. You simply use the Split function with the delimiter as parameter. The following code shows an example of using the Split function.



Sub StrToArr()

Dim arr() As String
' Parse string to array
arr = Split("John,Jane,Paul,Sophie", ",")

Dim name As Variant
For Each name In arr
Debug.Print name
Next

End Sub

Output

John

Jane

Paul

Sophie


Array to String using Join

If you want to build a string from an array you can do so easily using the Join function. This is essentially a reverse of the Split function. The following code provides an example of using Join



Sub ArrToStr()

Dim Arr(0 To 3) As String
Arr(0) = "John"
Arr(1) = "Jane"
Arr(2) = "Paul"
Arr(3) = "Sophie"

' Build string from array
Dim sNames As String
sNames = Join(Arr, ",")

Debug.Print sNames

End Sub

Output

John,Jane,Paul,Sophie


 


Formatting a String





FunctionParamsDescriptionExample




Formatexpression, format,
firstdayofweek, firstweekofyearFormats a string Format(0.5, "0.00%")





The Format function is used to format a string based on given instructions. It is mostly used to place a date or number in certain format. The examples below show the most common ways you would format a date.



Sub FormatDate()

Dim s As String
s = "31/12/2015 10:15:45"

' Prints: 31 12 15
Debug.Print Format(s, "DD MM YY")
' Prints: Thu 31 Dec 2015
Debug.Print Format(s, "DDD DD MMM YYYY")
' Prints: Thursday 31 December 2015
Debug.Print Format(s, "DDDD DD MMMM YYYY")
' Prints: 10:15
Debug.Print Format(s, "HH:MM")
' Prints: 10:15:45 AM
Debug.Print Format(s, "HH:MM:SS AM/PM")

End Sub

The following examples are some common ways of formatting numbers



Sub FormatNumbers()

' Prints: 50.00%
Debug.Print Format(0.5, "0.00%")
' Prints: 023.45
Debug.Print Format(23.45, "00#.00")
' Prints: 23,000
Debug.Print Format(23000, "##,000")
' Prints: 023,000
Debug.Print Format(23000, "0##,000")
' Prints: $23.99
Debug.Print Format(23.99, "$#0.00")

End Sub

The Format function is quite a large topic and could use up a full post on it’s own. If you want more information then the MSDN Format Page provides a lot of information.


Helpful Tip for Using Format

A quick way to figure out the formatting to use is by using the cell formatting on an Excel worksheet. For example add a number to a cell. Then  right click and format the cell the way you require. When you are happy with the format select Custom from the category listbox on the left.  When you select this you can see the format string in the type textbox(see image below). This is the string format you can use in VBA.


VBA Format Function

Format Cells Dialog


 


Conclusion

If you found this post useful then you’ll definitely enjoy my free eBook How to Ace 21 Most Common Questions in VBA. If you want to check out more posts on this blog then the complete list by category is available here.


 •  0 comments  •  flag
Share on Twitter
Published on July 13, 2015 10:33

April 23, 2015

The Ultimate Guide To Collections in Excel VBA

“I’m not a builder of buildings, I’m a builder of collections” – Leonard Lauder


The table below will show you how to use collections in VBA. For a simple and complete guide to Collections in VBA check out the rest of this post.


VBA Collection

A Quick Guide to VBA Collections


Introduction

Collections are a very important part of VBA.  If you have used the language for any length of time then you will have used Collections. The most common ones are the Workbooks, Worksheets, Range and Cells collections. The following code shows some examples of using the VBA Workbooks collection



' Workbooks is a collection of all open workbooks

' Count is the number of workbooks in the collection
Debug.Print Workbooks.Count

' Print the full name of the workbook called Example.xlsm
Debug.Print Workbooks("Example.xlsm").FullName

' Print the full name of the workbook that was opened second
Debug.Print Workbooks(2).FullName

Collections are similar to arrays so it is important to understand what they are and how the differ to arrays.


What is a Collection?
[image error]

© Vlaskoff | Dreamstime.com. A Collection of the old Soviet cars


 


Collections and arrays are both used to group variables. They both store a set of similar items e.g. a list of student marks or country names. Using a collection or array allows you to quickly and easily manipulate a large number of items.


In my post on arrays, I explained in simple terms what arrays are and why they are so useful. I will briefly recap this information here.


If you were storing the marks of one student then you can easily do this using a single variable



Dim mark As Long
mark = sheetMarks.Range("A1")

However most of the time you will have more than one student to deal with. Imagine you want to store the marks of 100 students. If you didn’t use collections or arrays you would need to create a hundred variables – one variable to store the mark for each student.


Another problem is that you have to use these variables individually. If you want to store 100 marks then you need a line of code each time you want to store a value to a variable.



' Declare a variable for each mark
Dim mark1 As Long
Dim mark2 As Long
.
.
.
Dim mark100 As Long

' Store the marks from the worksheet in a variable
mark1 = sheetMarks.Range("A1")
mark2 = sheetMarks.Range("A2")
.
.
.
mark100 = sheetMarks.Range("A100")

As you can see in the above example, writing code like this would mean hundreds of lines of repetitive code. When you use a collection or array you only need to declare one variable. Using a loop with a collection or arrays means you only need one line for add or reading values.


If we rewrite the above example using a collection then we only need a few lines of code



' Create collection
Dim collMarks As New Collection

' Read 100 values to collection
Dim c As Range
For Each c In Sheet1.Range("A1:A100")
' This line is used to add all the values
collMarks.Add c.Value
Next

 


Collections Vs Arrays?

We have looked at what collections and arrays have in common. So what is the difference and why use one over the other?


The main difference is that with an array you normally set the size once. This means that you know the size before you start adding elements. Let me explain this with an example.


Example: Where an Array is Better

Imagine you have a worksheet of student marks with one student per row


VBA Collection

Student Marks


You want to store information about each student. In this example you can easily count the number of rows to get the number of students. In other words you know the number of items in advance.



' Get last row - this is the number of students
Dim lStudentCount As Long
lStudentCount = Sheet1.Range("A" & Rows.Count).End(xlUp).Row

' Create array of correct size
Dim arr() As Long
ReDim arr(1 To lStudentCount)

In the example code you can see that we get the number of students by counting the rows. We can then use this to create an array of the correct size.


VBA Collections and Arrays


Let us now look at a second example where we don’t know the number of items in advance


Example Where a Collection is Better

In this example we have the same student worksheet but this time we only want the of students with a given criteria. For example only the students from the USA or England that study Maths or History. In other words you will not how to select a student until you read their details from the worksheet.


Imagine also that students can be added or removed from the list as the application runs.


So in this example the number of students is not fixed and changes a  lot. Here you do not know the number of students in advance. Therefore you do not know what size array to create.


You could create an array of the biggest possible size. The problem is you would have a lot of empty slots and would have to add code to deal with these. If you read 50 students from a max of 1000 then you would have 950 unused array slots.


You could also resize the array for each item as it is added. This is very inefficient and quite messy to do. So for this example using a collection would be better.



' Declare
Dim coll As New Collection

' Add item - VBA looks after resizing
coll.Add "Apple"
coll.Add "Pear"

' remove item - VBA looks after resizing
coll.Remove 1

When you add or remove an item to a collection VBA does all the resizing for you. You don’t have to specify the size or allocate new spaces. VBA does it under the hood. All you have to do is add an item or remove it.


Collections VBA


Another Advantage of Collections

Collections are much easier to use than arrays especially if you are new to programming. Most of the time you do three things with collections:



Create the collection
Add some items
Read through the items

So if you are not dealing with a larger number of items then using a Collection can be much neater to use.


A Disadvantage of Collections

Collections are read-only.You can add or remove an item but you cannot change the value of the item. If you are going to be changing the values in a group of items then you will need to use an array.


VBA collection readonly


Now that we know when and why to use a collection let’s look at how to use one.


How to Create a Collection

You can declare and create in one line as the following code does



' Declare and create
Dim coll As New Collection

As you can see you don’t need to specify the size. Once your collection has been created you can easily add items to it.


You can also declare and then create the collection if and when you need it.



' Declare
Dim coll As Collection

' Create Collection
Set coll = New Collection

 


Minor Difference Between These Methods

The difference between these methods is that for the first one the collection is always created. For the second method the collection is only created when the Set line is reached. So you could set the code to only create the collection if a certain condition was met



' Declare
Dim coll As Collection

' Create Collection if a file is found
If filefound = True Then
Set coll = New Collection
Endif

The advantage to using this method is minimal. Allocating memory was important back in the 1990’s when computer memory was limited. Unless you are creating a huge number of collections on a slow PC you will never notice any benefit.


Use Set means the collection will behave differently than when you set the collection to nothing. The next section explains this.


Removing All items from a Collection

To remove all items from a collection you can simply set it to nothing.



Set Coll = Nothing

An important point to understand here is that what this does depends on how you created the collection. As we saw you can create a Collection by declaring using New or by using Set and New. Let’s look at both types


Declaring Using New

If you set this collection to nothing then it will be set to the state where the “object is not set”. When you add a new item VBA automatically sets the Collection variable to a valid collection.


In other words if you set the collection to nothing it will empty all the items. If you then add an item to the collection you will now have a collection with one item. This makes it simple to empty a collection.


The following code demonstrates this.



Sub EmptyColl()

' Create collection and add items
Dim coll As New Collection

' add items here

' Empty collection
Set coll = Nothing

' Add item
coll.Add "Pear"

End Sub

A subtle point to emphasize here is that when you set the collection to Nothing it is not actually set to nothing. Therefore if you try to compare it with being it will not work.


Using Set and New

When you use Set to create a collection you must create the collection again if you set it to Nothing. In the following code after setting to nothing you must then set using new again. If you don’t do this you will get the error: “Object Variable or With block variable not set”.



Sub EmptyCollSet()

' Create collection
Dim coll As Collection
Set coll = New Collection

' Add items here

' Empty collection
Set coll = Nothing

' SET TO NEW BEFORE USING
Set coll = New Collection

' Add item
coll.Add "Pear"

End Sub

 


Remove All – An Alternative Method

The following method will also remove all the elements of a collection but is a slower way to do it. The advantage is that is will work no matter which way you create the collection.



Sub RemoveAll(ByRef coll As Collection)

Dim i As Long
For i = coll.Count To 1 Step -1
coll.Remove i
Next i

End Sub

 


Adding items to a Collection

It is simple to add items to a collection. You use the add property followed by the value you wish to add.



collFruit.Add "Apple"
collFruit.Add "Pear"

You can have any basic type in a collection such as a Double



collTotals.Add 45.67
collTotals.Add 34.67

When you add items in this manner they are added to the next available index. In the fruit example, Apple is added to position 1 and Pear to position 2.


Before and After

You can use the Before or After parameters to specify where you want to place the item in the collection. Note you cannot use both of these arguments at the same time.



collFruit.Add "Apple"
collFruit.Add "Pear"
' Add lemon before first item
collFruit.Add "Lemon" Before:=1

After this code the collection is in the order

1. Lemon

2. Apple

3. Pear



collFruit.Add "Apple"
collFruit.Add "Pear"
' Add lemon after first item
collFruit.Add "Lemon" After:=1

After this code the collection is in the order

1. Apple

2. Lemon

3. Pear


Accessing Items of a Collection

To Access the items of a collection you simply use the index. As we saw the index is the position of the item in the collection based on the order they were added. The order can also be set using the Before or After parameter.



Sub access()

Dim coll As New Collection

coll.Add "Apple"
coll.Add "Pear"

' Will print Apple
Debug.Print coll(1)

' Add orange first
coll.Add "Orange", Before:=1

' Will print Orange
Debug.Print coll(1)

' Will print Apple as it is now in position 2
Debug.Print coll(2)

End Sub

You can also use the Item Property to access an item in the collection. It is the default method of the collection so the followling lines of code are equivalent



Debug.Print coll(1)
Debug.Print coll.Item(1)

 


Items in a collection are Read Only

This is a very important point. You cannot change the value of an item in a collection. When you access an item from a collection it is read only. If you try to write to a collection item you will get an error. The following code produces an “object required” error



Sub WriteValue()

Dim coll As New Collection

coll.Add "Apple"

' This line causes an ERRROR
coll(1) = "Pear"

End Sub

 


Adding different types

You can also add different types of items to a collection.



collFruit.Add "Apple"
collFruit.Add 45
collFruit.Add #12/12/2017#

This is seldom needed. In VBA the Sheets collections contains sheets of type Worksheet and of type Chart. (To create a Chart sheet simple right click on any Chart, select Move and select the radio button for New sheet).


The following code displays the type and name of all the sheets in the current workbook. Note to access different type you need the For Each variable to be a variant or you will get an error.



Sub ListSheets()

Dim sh As Variant
For Each sh In ThisWorkbook.Sheets
' Display type and name of sheet
Debug.Print TypeName(sh), sh.Name
Next

End Sub

When you access different items the For Each variable must be a variant. If it’s not you will get an error when you access a different type than you declared. If we declared sh as a worksheet in the above example it would give an error when we try to access a sheet of type Chart.


It is rare that you would need a collection of different types but as you can see sometimes it can be useful.


Adding Items Using a Key

You can also add items using a key as the next example shows



collMark.Add Item:=45, Key:="Bill"

Debug.Print "Bill's Marks are: ",collMark("Bill")

I included the parameter names to make the above example clear. However you don’t need to do this. Just remember the key is the second parameter and must be a unique string.


The following code shows a second example of using  keys



Sub UseKey()

Dim collMark As New Collection

collMark.Add 45, "Bill"
collMark.Add 67, "Hank"
collMark.Add 12, "Laura"
collMark.Add 89, "Betty"

' Print Betty's marks
Debug.Print collMark("Betty")

' Print Bill's marks
Debug.Print collMark("Bill")

End Sub

Using keys is has three advantages:



If the order changes your code will still access the correct item
You can directly access the item without reading through the entire collection
It can make you code more readable

In the VBA Workbooks collection it is much better to access the workbook by the key(name) the by the index.  The order is dependent on when they were opened and so is quite random.



Sub UseAWorkbook()

Debug.Print Workbooks("Example.xlsm").Name

Debug.Print Workbooks(1).Name

End Sub

 


When to Use Keys

An example of when to use keys is as follows: Imagine you have a collection of IDs for a 10,000 students along with their marks.


You also have a number of worksheet reports that have lists of student IDs. For each of these worksheets you need to print the mark for each student.


You could do this by adding the 10,000 students to a collection using their student id as they key. When you read an ID from the worksheet you can directly access this student’s marks.


If you didn’t use a key you would have to search through 10,000 IDs for each ID on the report.


Shortcoming of Using Keys in Collections

There are three issues with using keys in collections



You cannot check if the key exists
You cannot change the key
You cannot retrieve the key

VBA contains a class similar to the Collection called the Dictionary. With a Dictionary you always use keys to add an item. The Dictionary provides more functionality to work with keys. If you need more functionality with keys then you may find the Dictionary very useful.


Coming back to Collections: if you will need to directly access a single item then using keys can be very useful. Otherwise you don’t need to use them.


Accessing all items in a Collection

To access all the items in a collection you can use a For loop or a For Each loop. Let’s look at these individually.


Using the For Loop

With a normal For Loop, you use the index to access each item. The following example prints the name of all the open workbooks



Sub AllWorkbook()

Dim i As Long
For i = 1 To Workbooks.Count
Debug.Print Workbooks(i).Name
Next i

End Sub

You can see that we use the range of 1 to Workbooks.Count. The first item is always in postion one and the last item is always in the position specified by the Count property of the collection.


The next example prints out all the items in a user created collection.



Sub UserCollection()

' Declare and Create collection
Dim collFruit As New Collection

' Add items
collFruit.Add "Apple"
collFruit.Add "Pear"
collFruit.Add "Plum"

' Print all items
Dim i As Long
For i = 1 To collFruit.Count
Debug.Print collFruit(i)
Next i

End Sub


 


Using the For Each

The For Each loop that is a specialised loop the is used for Collections. It doesn’t use the index and the format is shown in the following example



Sub AllWorkbookForEach()

Dim book As Variant
For Each book In Workbooks
Debug.Print book.Name
Next

End Sub

The format of the For loop is:

For i = 1 To Coll.Count

Next

where i is a long and Coll is a collection.


The format of the For Each Loop is:

For Each var In Coll

Next

where var is a variant and Coll is a collection.


To access each the item

For: Coll(i)

For Each: Var


The following example shows the loops side by side for the above user collection example




Sub UseBothLoops()

' Declare and Create collection
Dim collFruit As New Collection

' Add items
collFruit.Add "Apple"
collFruit.Add "Pear"
collFruit.Add "Plum"

' Print all items using For
Dim i As Long
For i = 1 To collFruit.Count
Debug.Print collFruit(i)
Next i

' Print all items using For Each
Dim fruit As Variant
For Each fruit In collFruit
Debug.Print fruit
Next fruit

End Sub


 


For Each Versus For

It is important to understand the difference between the two loops.


The For Each Loop



is faster
is neater to write
has one order  only – low index to high

The For Loop



is slower
is less neater to write
can access in different order

Let’s  compare the loops under each of these attributes


Speed

The For Each is considered faster than the For Loop. Nowadays this is only an issue if you have a large collection and/or a slow PC/Network.


Neater

The For Each loop is neater to write especially if you are using nested loops. Compare the following loops. Both print the names of all the worksheets in open workbooks.



Sub PrintNamesFor()

' Print worksheets names from all open workbooks
Dim i As Long, j As Long
For i = 1 To Workbooks.Count
For j = 1 To Workbooks(i).Worksheets.Count
Debug.Print Workbooks(i).Name, Workbooks(i).Worksheets(j).Name
Next j
Next i

End Sub

Sub PrintNamesForEach()

' Print worksheets names from all open workbooks
Dim bk As Workbook, sh As Worksheet
For Each bk In Workbooks
For Each sh In bk.Worksheets
Debug.Print bk.Name, sh.Name
Next sh
Next bk

End Sub

The For Each loop is much neater to write and less likely to have errors.


Order

The order of the For Each loop is always from the lowest index to the highest. If you want to get a different order then you need to use the For Loop. The order of the For Loop can be changed. You can read the items in reverse. You can read a section of the items or you can read every second item.




Sub ReadRightToLeft()

' Go through sheets from right to left
Dim i As Long
For i = ThisWorkbook.Worksheets.Count To 1 Step -1
Debug.Print ThisWorkbook.Worksheets(i).Name
Next i

' Go through first 3 sheets
For i = 1 To 3
Debug.Print ThisWorkbook.Worksheets(i).Name
Next i

' Go through every second sheet
For i = 1 To ThisWorkbook.Worksheets.Count Step 2
Debug.Print ThisWorkbook.Worksheets(i).Name
Next i

End Sub

The For loop gives more flexibility here but the reality is that most of the time the basic order is all you need.



Using Collections with Functions and Subs

Using a Collection as a parameter or return value is very easy to do. We will look at them in turn.


Passing a Collection to a Sub/Function

It is simple to pass a collection to a function or sub. It is passed like any parameter as the following code example shows



Sub UseColl()

' Create collection
Dim coll As New Collection

' Add items
coll.Add "Apple"
coll.Add "Orange"

' Pass to sub
PrintColl coll

End Sub

' Sub takes collection as argument
Sub PrintColl(ByRef coll As Collection)

Dim item As Variant
For Each item In coll
Debug.Print coll
Next

End Sub

You can see how useful the sub PrintColl is in the example. It will print all the elements of ANY collection. The size or type of element does not matter. This shows how flexible collections are to use.


Passing ByVal versus ByRef

One subtle point to keep in mind here is passing by value(By Val) and passing by reference(ByRef) differ slightly.


For a simple variable passing by value means a copy is created. This means if the Function/Sub changes the value will not be changed when you return to the calling procedure.


In the following example we pass total using both ByVal and ByRef. You can see that after we pass using ByRef the value has changed in the calling procedure.



Sub PassType()

Dim total As Long
total = 100

PassByVal total
' Prints 100
Debug.Print total

PassByRef total
' Prints 555
Debug.Print total

End Sub

Sub PassByVal(ByVal total As Long)
' value changed only in this sub
total = 555
End Sub

Sub PassByRef(ByRef total As Long)
' value also changed outside this sub
total = 555
End Sub


Using ByVal and ByRef with a Collection is a bit different. If you add or remove item then the collection in the original caller will also be changed. So the Subs in the following example will both remove the first item of the original collection



Sub RemoveByRef(ByRef coll As Collection)
coll.Remove 1
End Sub

Sub RemoveByVal(ByVal coll As Collection)
coll.Remove 1
End Sub

The reason for this is that a Collection variable contains a pointer. This means it contains the address of the collection rather than the actual collection. So when you add or remove an item you are changing what the pointer is pointing at and not the pointer itself. However if you change the pointer it will be changed outside of the sub.


You don’t need to worry about pointers. All you need to know is how this affects the behaviour of passing a parameter. If you set a collection parameter to nothing then the behaviour depends on if you used ByRef or ByVal.



Using ByRef will reset the original collection
Using ByVal will not change the original collection


' Will empty original collection
Sub PassByRef(ByRef coll As Collection)
Set coll = Nothing
End Sub

' Will NOT empty original collection
Sub PassByVal(ByVal coll As Collection)
Set coll = Nothing
End Sub

 


Returning a Collection From a Function

Returning a collection from a Function is the same as returning any object. You need to use the Set keyword. In the following example you can see how to return a collection



Sub FruitReport()

Dim coll As Collection
' assign coll to return value
Set coll = CreateCollection

End Sub

Function CreateCollection() As Collection

Dim coll As New Collection

coll.Add "Plum"
coll.Add "Pear"

' Return collection
Set ReadFruit = coll

End Function

Note that you don’t use the New keyword when declaring the collection in the sub FruitReport(). This is because the collection is created in CreateCollection(). When you return the collection you are simple assigning the collection variable to point to this collection.


Conclusion

Collections are a very useful part of VBA. There are much easier to use than Arrays and are very useful when the number of items changes a lot. They have only four properties: Add, Remove, Count and Item. This makes them very easy to master.


I hope you found this post useful. This blog has loads more posts on the important areas of VBA. You can check out all the posts by category here. If you have any queries feel free to email me at paulkellykk@gmail.com.


 •  0 comments  •  flag
Share on Twitter
Published on April 23, 2015 04:09

April 17, 2015

How To Dramatically Reduce VBA Errors

“I am indeed amazed when I consider how weak my mind is and how prone to error.” – Rene Descartes


Introduction

This post shows a simple technique that will vastly reduce the number of errors in your VBA code. I have used this technique thousands of times on countless projects. It will save you considerable time creating applications and it will make your application practically bulletproof.


If you adopt this technique then I guarantee you will see results almost immediately. Reading about it is not enough – you have to actually try it out for yourself. Once you see how useful it is you will want to keep using it.


The simple technique I’m referring to is the Assertion statement. It  is simple to use and implement and will provide dramatic results. However don’t be fooled by the simplicity of an Assertion. Used correctly it is an incredibly powerful way of detecting errors in your code.


Before we look at Assertions lets have a quick look at a startling fact about errors


VBA Debug.Assert

© Wotan777 | Dreamstime.com
A Proud Warrior On The Field At Dawn


A Startling Fact About Errors in Code

According to Steve McConnell in Code Complete: “there are about 15 – 50 errors per 1000 lines of delivered code”.


Just think about this for a moment. If you average the time on each bug to 30 minutes then your are talking 8 to 25 hours spent on errors for every 1000 lines of code.


30 Minutes is an optimistic average. When a bug is found in delivered code many of the following steps are required



Reproduce the bug
Emails about details of the issue
Find the bug
Fix the bug
Update the Bug Report
Create new version of the code
Test the new version
and so on

If you find a bug in development



Find the problem and fix it

This leads us to the following rule


VBA Debug.Assert


Therefore finding bugs early and close to the cause is a priority. Let’s have a look at your first line of defence when it comes to errors. Then we will look at Assertions


The Front Line in the War on Errors

In VBA there are some basic tools for finding errors. These are very important for catching errors before you run your code. So it’s vital that you use them in your development.  I’m going to briefly mention them here.


The Interpreter : The interpreter in VBA checks each line of code as you write it. When you press return it will check for errors in the line and display the error if it finds one. See here for a downloadable list of common errors and how to resolve them.


The Compiler : Before you run your code you should always compile it to find any existing errors. To compile select Debug->Compile VBAProject  from the menu.


Note: If you Run your code(Run->Run Macro from menu) it will find some of the same errors. However it will only check in the code that is being run.


Review Source Code from Mz-Tools: MZ-Tools is great free tool that provides extra functionality to the VBA Editor that includes reviewing the source code. This review looks for items such as unused variables, parameters and other useful items.


To use this tool select Other Utilities->Review Source Code from the MZ-Tools toolbar


VBA Bugs

Using the MZ-Tool to Review Code


Now that we have covered the basic error finding methods lets look at using Assertions.


Why Use Assertions

We have just looked at ways of detecting errors in your code. However certain errors will not appear until you run it. This is where Assertions come into play.  A great description of Assertions can be found in the book Debugging Windows Programs (2000 Developmentor Series)


“You can add information to your code to have the program itself automatically detect many types of run-time errors”


The key phrase here is “automatically detect”. Once you add Assertions to your code they will automatically check for errors each time you run your code. This makes it very difficult for many types of errors to exist. So running your code with Assertions is a fantastic way of smoking out errors.


What are Assertions

Assertions are used in development to check your code as it runs. An Assertion is a statement that evaluates to true or false. If it evaluates to false then the code stops at that line. This is useful as it stops you close to the cause of the error.


Let’s explain using an analogy. Imagine the different paths through your code were the streets of a city and variables were vans that drove the streets. Assertions would then be checkpoints that ensure the vans(variables) contain valid goods(values) before they are allowed to pass.


VBA Assertion

© Marcogarrincha | Dreamstime.com


If the city was full of checkpoints it would be very difficult for the Van to travel far with invalid goods. It’s the same with code. The more Assertions there are the harder for the code to run for long with errors.


In the city solution the checkpoints would affect performance. They would slow the city traffic considerably. With Assertions there are no performance issues. They are turned off when you deliver your software to the user. This means you can add as many Assertions as you like and it will have no affect on how your code runs.


How to Create A VBA Assertion

It is simple to create an assertion in VBA.  You use the function Debug.Assert followed by a Condition.



Debug.Assert Worksheets.Count > 0
Debug.Assert Text <> ""

Here are some more examples



' This will fail if readRow is not 1 or greater
Dim readRow As Long
Debug.Assert readRow > 0

' This will fail if month is not between 1 and 12
Dim month As Long
Debug.Assert month >= 1 And month

When the code meets a Debug.Assert line it evaluates the condition. If the condition evaluates to false then the code stops on this line. If it evaluates to true then the code simply continues on.


When to Use Assertions

The best way to use Assertions is to test the following items:



The input values of a Sub/Function
A value before it is returned from a function
A value that is received from a function
A global variable before it is used

The following functions uses Assertions to test



the values of the input parameters (Precondition)
the value that is being returned(Postcondition)


Function GetType(price As Long, shipType As String) As Double

' TEST THE INPUTS(Preconditions)
Debug.Assert price > 0 And price < 100 Debug.Assert Len(shipType) = 1 ' Do some calcus Dim newVal As Double If shipType = "A" Then newVal = price 3.99 ElseIf shipType = "B" Then newVal = price 5.99 Else newVal = price 0 End If ' TEST THE RETURN VALUE(Postconditions) Debug.Assert newVal > 0

' Return the value
GetType = newVal

End Function

In the next example we use an Assertion to test the return value from a function



Sub RunReport()

Dim total as long
total = CalculateTotal()
    ' check that total is in the expected range(1 to 999)
Debug.Assert total>0 and total

 


Assertions Versus Error Handling

Error handling is used in code to anticipate error conditions and deal with them. For example sometimes a workbook you are trying to open my have been moved, deleted or renamed. In this case the code should report the error and return to the state before it tried to use this file.


Let’s look at a second example. Imagine you use a software application to play music files. If you try to play an invalid file the application should inform you the file is incompatible. The application should then return to it’s previous state – ready for you to select a file to play as if nothing happened. The application not stop working or begin working incorrectly.


The following code shows a simple example of error handling. We use the Dir function to check the file exists. If not then we inform the user there is a problem. We only attempt to open the file when we know it actually exists.



Sub ReadData(ByVal filename As String)

' Use Dir to check the file exists
If Dir(filename) = "" Then
' Tell the user the file does not exist
MsgBox "Could not find the file " filename
Else
' Open workbook
Workbooks.Open filename
End If

End Sub

The difference between Assertions and Error Handling is that



Assertions deal with values coming from an internal source
Assertions are used to inform the programmer of errors and not the user
Error Handling deals with errors coming from an external source e.g. opening files, user input, spreadsheet data etc.

Let’s update the example above so it uses both Assertions and Error Handling.



Sub ReadData(ByVal filename As String)

' USE ASSERTION TO CHECK VALUES FROM INSIDE APPLICATION
Debug.Assert filename <> ""

' USE ERROR HANDLING TO DEAL WITH ERRORS FROM OUTSIDE APPLICATION
' Use Dir to check the file exists
If Dir(filename) = "" Then
' Inform the user
MsgBox "Could not find the workbook: " filename
Else
' Open workbook
Workbooks.Open filename
End If

End Sub

If these seems confusing just remember you mostly use assertions on arguments and return values.


 


How to Turn Assertions On or Off

Assertions are used to check your code during development or maintenance. When you give your application to a user then you turn the Assertions off. This provides us with two really great advantages:



You can add as many Assertions as you like as it will not have any impact on the code you give the user
If in doubt about adding an Assertion then add it anyway. You can easily remove it and it won’t affect the user.

Let’s look at how to turn Assertions On and Off.


To turn Assertions On/Off we use a special type of If statement to surround our code. This is the #If statement – note the #character before the If . First of all we need to create a “Conditional Argument” that we can use in this if statement


Select Tool->VBAProject Properties from the VBA menu.


 


VBA Conditional Argument


 


You can see in the screen shot that we have written Debugging = 1 in the cryptically named textbox “Conditional Compilation Arguments”. Debugging can be any name we like and =1  means it is currently true.


We use this argument to decide if we are going to use certain code when our application runs. The following code shows how to use the #If statement with the compilation argument i.e. in this case Debugging



Function GetType(price As Long, shipType As String) As Double

#If Debugging Then
' Test inputs(Preconditions)
Debug.Assert price > 0 And price < 100
Debug.Assert Len(shipType) = 1
#End If

End Function

In the above example the assertions are only used when Debugging is turned on(set to a value other than 0). When we turn debugging off this code will not be used. When we want to turn off the Assertions we simply change the Conditional Argument in the dialog to Debugging = 0. This means all the code inside the #If Debugging statements will not be used.


 


What to Avoid

Never put executable code inside a #If statement. Only use code that will help you when debugging. In VBA this is essentially the two statement types Debug.Assert and Debug.Print. The second statement writes to the Immediate Window(Ctrl G or View->Immediate Window from Menu) and it useful for testing code.


The following example is something you should avoid doing




#If Debugging Then
' Don't use executable inside #If statements
Debug.Assert WriteData() = True
#End If

End Sub

Function WriteData() As Boolean
WriteData = False
End Function


The correct way to write this code is shown in the following example



Sub TestAssert()

Dim success As Boolean
success = WriteData()

#If Debugging Then
Debug.Assert success = True
#End If

End Sub

Function WriteData() As Boolean

WriteData = False

End Function

In the second example there is no executable code in the #If statement. This is important as it means the code will run exactly the same when you turn debugging on or off.


Using Assertions With Collections and Objects

When you are using a Collection you should check two things:



If the Collection has been created
If the collection has elements

Lets look at how to create a collection. We can declare in one line and create in a second line like this code shows



Sub CreateCollection1()

' Declare a collection variable
Dim coll As Collection
' Assign coll to a new empty collection
Set coll = New Collection

End Sub

we can also declare and create in one single line as the next example shows.



Sub CreateCollection2()

' Declare and create collection in one line
Dim coll As New Collection

End Sub

In the first example the variable Coll is set to Nothing until we use the Set command to create a new Collection for it.


So when using Collections(or any object) we need first to check they are not empty(Set to Nothing). The following example shows how to check an object is set to something



Sub TestCollection(coll As Collection)

Debug.Assert Not coll Is Nothing

End Sub

This code may seem strange as it has two negatives – Not and Nothing. However all objects are tested this way so you can use it even if you don’t understand it at first.


The next example shows Assertions that test a Workbook and Worksheet object to ensure they have been assigned to something.



Sub WriteData(wk As Workbook, sh As Worksheet)

Debug.Assert Not wk Is Nothing
Debug.Assert Not sh Is Nothing

End Sub

When using Collections it is also a good idea to check that it contains some elements



Sub TestCollection(coll As Collection)

Debug.Assert Not coll Is Nothing
Debug.Assert coll.Count >= 1

End Sub

 


Summary

The following is a summary of the main points of this post



Finding errors early is vital
It will save time and improve quality
Assertions find errors during run time
Assertions are created in VBA using Debug.Assert
They are used during development and mantainence
Assertions are not a substitute for error handling code
Assertions provide information to the programmer not the user
If in doubt add the Assertion anyway. You can easily remove it from the code.
Assertions are turned off when the code is released. It is simple to do this in VBA.

Major Advantages of Assertions



It is simple to add them to your code
They automatically detect errors when your code is running
They have no performance issues as you turn them off upon release.

I hope you found this post beneficial  and that it conveyed how useful Assertions are. They really are a fantastic tool and will greatly improve your programming experience.


Please feel free to subscribe to my newsletter and get exclusive VBA content that you cannot find here on the blog, as well as free access to my eBook, How to Ace the 21 Most Common Questions in VBA which is full of examples you can use in your own code.

Free VBA eBook


The post How To Dramatically Reduce VBA Errors appeared first on Excel Macro Mastery.

 •  0 comments  •  flag
Share on Twitter
Published on April 17, 2015 06:33

How To Reduce VBA Errors by up to 70% Using This Proven Technique

“I am indeed amazed when I consider how weak my mind is and how prone to error.” – Rene Descartes


VBA Assertion

© Wotan777 | Dreamstime.com
A Proud Warrior On The Field At Dawn


Introduction

This post shows a simple technique that will vastly reduce the number of errors in your VBA code. I have used this technique thousands of times on countless projects. It will save you considerable time creating applications and it will make your application practically bulletproof.


If you adopt this technique then I guarantee you will see results almost immediately. Reading about it is not enough – you have to actually try it out for yourself. Once you see how useful it is you will want to keep using it.


The simple technique I’m referring to is the Assertion statement. It  is simple to use and implement and will provide dramatic results. However don’t be fooled by the simplicity of an Assertion. Used correctly it is an incredibly powerful way of detecting errors in your code.


Before we look at Assertions lets have a quick look at a startling fact about errors


A Startling Fact About Errors in Code

According to Steve McConnell in Code Complete: “there are about 15 – 50 errors per 1000 lines of delivered code”.


Just think about this for a moment. If you average the time on each bug to 30 minutes then your are talking 8 to 25 hours spent on errors for every 1000 lines of code.


30 Minutes is an optimistic average. When a bug is found in delivered code many of the following steps are required



Reproduce the bug
Emails about details of the issue
Find the bug
Fix the bug
Update the Bug Report
Create new version of the code
Test the new version
and so on

If you find a bug in development



Find the problem and fix it

This leads us to the following rule


VBA Debug.Assert


Therefore finding bugs early and close to the cause is a priority. Let’s have a look at your first line of defence when it comes to errors. Then we will look at Assertions


The Front Line in the War on Errors

In VBA there are some basic tools for finding errors. These are very important for catching errors before you run your code. So it’s vital that you use them in your development.  I’m going to briefly mention them here.


The Interpreter : The interpreter in VBA checks each line of code as you write it. When you press return it will check for errors in the line and display the error if it finds one. See here for a downloadable list of common errors and how to resolve them.


The Compiler : Before you run your code you should always compile it to find any existing errors. To compile select Debug->Compile VBAProject  from the menu.


Note: If you Run your code(Run->Run Macro from menu) it will find some of the same errors. However it will only check in the code that is being run.


Review Source Code from Mz-Tools: MZ-Tools is great free tool that provides extra functionality to the VBA Editor that includes reviewing the source code. This review looks for items such as unused variables, parameters and other useful items.


To use this tool select Other Utilities->Review Source Code from the MZ-Tools toolbar


VBA Bugs

Using the MZ-Tool to Review Code


Now that we have covered the basic error finding methods lets look at using Assertions.


Why Use Assertions

We have just looked at ways of detecting errors in your code. However certain errors will not appear until you run it. This is where Assertions come into play.  A great description of Assertions can be found in the book Debugging Windows Programs (2000 Developmentor Series)


“You can add information to your code to have the program itself automatically detect many types of run-time errors”


The key phrase here is “automatically detect”. Once you add Assertions to your code they will automatically check for errors each time you run your code. This makes it very difficult for many types of errors to exist. So running your code with Assertions is a fantastic way of smoking out errors.


What are Assertions

Assertions are used in development to check your code as it runs. An Assertion is a statement that evaluates to true or false. If it evaluates to false then the code stops at that line. This is useful as it stops you close to the cause of the error.


Let’s explain using an analogy. Imagine the different paths through your code were the streets of a city and variables were vans that drove the streets. Assertions would then be checkpoints that ensure the vans(variables) contain valid goods(values) before they are allowed to pass.


VBA Assertion

© Marcogarrincha | Dreamstime.com


If the city was full of checkpoints it would be very difficult for the Van to travel far with invalid goods. It’s the same with code. The more Assertions there are the harder for the code to run for long with errors.


In the city solution the checkpoints would affect performance. They would slow the city traffic considerably. With Assertions there are no performance issues. They are turned off when you deliver your software to the user. This means you can add as many Assertions as you like and it will have no affect on how your code runs.


How to Create A VBA Assertion

It is simple to create an assertion in VBA.  You use the function Debug.Assert followed by a Condition.



Debug.Assert Worksheets.Count > 0
Debug.Assert Text <> ""

Here are some more examples



' This will fail if readRow is not 1 or greater
Dim readRow As Long
Debug.Assert readRow > 0

' This will fail if month is not between 1 and 12
Dim month As Long
Debug.Assert month >= 1 And month

When the code meets a Debug.Assert line it evaluates the condition. If the condition evaluates to false then the code stops on this line. If it evaluates to true then the code simply continues on.


When to Use Assertions

The best way to use Assertions is to test the following items:



The input values of a Sub/Function
A value before it is returned from a function
A value that is received from a function
A global variable before it is used

The following functions uses Assertions to test



the values of the input parameters (Precondition)
the value that is being returned(Postcondition)


Function GetType(price As Long, shipType As String) As Double

' TEST THE INPUTS(Preconditions)
Debug.Assert price > 0 And price < 100
Debug.Assert Len(shipType) = 1

' Do some calcus
Dim newVal As Double
If shipType = "A" Then
newVal = price + 3.99
ElseIf shipType = "B" Then
newVal = price + 5.99
Else
newVal = price + 0
End If

' TEST THE RETURN VALUE(Postconditions)
Debug.Assert newVal > 0

' Return the value
GetType = newVal

End Function

In the next example we use an Assertion to test the return value from a function



Sub RunReport()

Dim total as long
total = CalculateTotal()
    ' check that total is in the expected range(1 to 999)
Debug.Assert total>0 and total

 


Assertions Versus Error Handling

Error handling is used in code to anticipate error conditions and deal with them. For example sometimes a workbook you are trying to open my have been moved, deleted or renamed. In this case the code should report the error and return to the state before it tried to use this file.


Let’s look at a second example. Imagine you use a software application to play music files. If you try to play an invalid file the application should inform you the file is incompatible. The application should then return to it’s previous state – ready for you to select a file to play as if nothing happened. The application not stop working or begin working incorrectly.


The following code shows a simple example of error handling. We use the Dir function to check the file exists. If not then we inform the user there is a problem. We only attempt to open the file when we know it actually exists.



Sub ReadData(ByVal filename As String)

' Use Dir to check the file exists
If Dir(filename) = "" Then
' Tell the user the file does not exist
MsgBox "Could not find the file " + filename
Else
' Open workbook
Workbooks.Open filename
End If

End Sub

The difference between Assertions and Error Handling is that



Assertions deal with values coming from an internal source
Assertions are used to inform the programmer of errors and not the user
Error Handling deals with errors coming from an external source e.g. opening files, user input, spreadsheet data etc.

Let’s update the example above so it uses both Assertions and Error Handling.



Sub ReadData(ByVal filename As String)

' USE ASSERTION TO CHECK VALUES FROM INSIDE APPLICATION
Debug.Assert filename <> ""

' USE ERROR HANDLING TO DEAL WITH ERRORS FROM OUTSIDE APPLICATION
' Use Dir to check the file exists
If Dir(filename) = "" Then
' Inform the user
MsgBox "Could not find the workbook: " + filename
Else
' Open workbook
Workbooks.Open filename
End If

End Sub

If these seems confusing just remember you mostly use assertions on arguments and return values.


 


How to Turn Assertions On or Off

Assertions are used to check your code during development or maintenance. When you give your application to a user then you turn the Assertions off. This provides us with two really great advantages:



You can add as many Assertions as you like as it will not have any impact on the code you give the user
If in doubt about adding an Assertion then add it anyway. You can easily remove it and it won’t affect the user.

Let’s look at how to turn Assertions On and Off.


To turn Assertions On/Off we use a special type of If statement to surround our code. This is the #If statement – note the #character before the If . First of all we need to create a “Conditional Argument” that we can use in this if statement


Select Tool->VBAProject Properties from the VBA menu.


 


VBA Conditional Argument


 


You can see in the screen shot that we have written Debugging = 1 in the cryptically named textbox “Conditional Compilation Arguments”. Debugging can be any name we like and =1  means it is currently true.


We use this argument to decide if we are going to use certain code when our application runs. The following code shows how to use the #If statement with the compilation argument i.e. in this case Debugging



Function GetType(price As Long, shipType As String) As Double

#If Debugging Then
' Test inputs(Preconditions)
Debug.Assert price > 0 And price < 100
Debug.Assert Len(shipType) = 1
#End If

End Function

In the above example the assertions are only used when Debugging is turned on(set to a value other than 0). When we turn debugging off this code will not be used. When we want to turn off the Assertions we simply change the Conditional Argument in the dialog to Debugging = 0. This means all the code inside the #If Debugging statements will not be used.


 


What to Avoid

Never put executable code inside a #If statement. Only use code that will help you when debugging. In VBA this is essentially the two statement types Debug.Assert and Debug.Print. The second statement writes to the Immediate Window(Ctrl G or View->Immediate Window from Menu) and it useful for testing code.


The following example is something you should avoid doing




#If Debugging Then
' Don't use executable inside #If statements
Debug.Assert WriteData() = True
#End If

End Sub

Function WriteData() As Boolean
WriteData = False
End Function


The correct way to write this code is shown in the following example



Sub TestAssert()

Dim success As Boolean
success = WriteData()

#If Debugging Then
Debug.Assert success = True
#End If

End Sub

Function WriteData() As Boolean

WriteData = False

End Function

In the second example there is no executable code in the #If statement. This is important as it means the code will run exactly the same when you turn debugging on or off.


Using Assertions With Collections and Objects

When you are using a Collection you should check two things:



If the Collection has been created
If the collection has elements

Lets look at how to create a collection. We can declare in one line and create in a second line like this code shows



Sub CreateCollection1()

' Declare a collection variable
Dim coll As Collection
' Assign coll to a new empty collection
Set coll = New Collection

End Sub

we can also declare and create in one single line as the next example shows.



Sub CreateCollection2()

' Declare and create collection in one line
Dim coll As New Collection

End Sub

In the first example the variable Coll is set to Nothing until we use the Set command to create a new Collection for it.


So when using Collections(or any object) we need first to check they are not empty(Set to Nothing). The following example shows how to check an object is set to something



Sub TestCollection(coll As Collection)

Debug.Assert Not coll Is Nothing

End Sub

This code may seem strange as it has two negatives – Not and Nothing. However all objects are tested this way so you can use it even if you don’t understand it at first.


The next example shows Assertions that test a Workbook and Worksheet object to ensure they have been assigned to something.



Sub WriteData(wk As Workbook, sh As Worksheet)

Debug.Assert Not wk Is Nothing
Debug.Assert Not sh Is Nothing

End Sub

When using Collections it is also a good idea to check that it contains some elements



Sub TestCollection(coll As Collection)

Debug.Assert Not coll Is Nothing
Debug.Assert coll.Count >= 1

End Sub

 


Summary

The following is a summary of the main points of this post



Finding errors early is vital
It will save time and improve quality
Assertions find errors during run time
Assertions are created in VBA using Debug.Assert
They are used during development and mantainence
Assertions are not a substitute for error handling code
Assertions provide information to the programmer not the user
If in doubt add the Assertion anyway. You can easily remove it from the code.
Assertions are turned off when the code is released. It is simple to do this in VBA.

 

Major Advantages of Assertions



It is simple to add them to your code
They automatically detect errors when your code is running
They have no performance issues as you turn them off upon release.

 

I hope you found this post beneficial  and that it conveyed how useful Assertions are. They really are a fantastic tool and will greatly improve your programming experience.


This blog provides many other in-depth posts on the important areas of VBA. These will help you get the best from this fantastic Excel programming language. You can check out all the posts here.


 


 •  0 comments  •  flag
Share on Twitter
Published on April 17, 2015 06:33

April 13, 2015

The Complete Guide to Functions and Subs in Excel VBA

“I’m happy to share what I can, because I’m in it for the love of programming.” – John Carmack, creator of Doom, Quake  and Oculus VR.


VBA Functions and Subs

© Ariwasabi | Dreamstime.com


 


Introduction

What are Functions and Subs?


Functions and Sub are are very similar in VBA. They are both procedures where you write your code. However there are differences and these are important to understand. In this post I am going to look at Fuctions and Sub in detail and answer the vital questions including



What is the difference between them
When to use a Sub and when to use a Function?
How do you run them?
Can I return values
How do I pass parameters to them
What are optional parameters
and much more

If are looking for a quick guide to using Functions and Subs then go to the first section. However make sure to come back to the post as it has important information about using Functions and Subs that you don’t want to miss out on.


 


Functions and Subs: A Quick Guide

The following table provides a simple overview of using Functions and Subs.


A Quick Guide to Subs and Functions

A Quick Guide to Subs and Functions


 Note: A Function can also be called like a Sub when you are not returning a value.


 


What is a Sub?

In Excel VBA a Sub and a Macro are exactly the same thing! This often leads to confusion so it is a good idea to remember it. For the rest of this post I will refer to them as Subs.


A Sub/Macro is where you write your VBA code. When you run a Sub all the lines of code it contains are executed.


The following is an example of an empty sub



Sub WriteValues()

End Sub

You declare the Sub by using Sub and the name. When you give it a name keep the following in mind



The name must begin with a letter and cannot contain spaces.
The name must be unique in the current workbook

The end of the Sub is marked by the line End Sub.


When you create your Sub you can add some code like the following example shows



Sub WriteValues()
Range("A1") = 6
End Sub

 


What is a Function?

A Function is very similar to a Sub. The major difference is that a Function can return a value – a Sub cannot. There are other differences which we will look at but this is the main one.


You normally create a function when you want to return a value.


Creating a Function is similar  to creating a Sub



Function PerformCalc()

Function Sub

It is optional to add a return type to a function. However it is considered good practice to do so. If you accidentally return the wrong type then it will be flagged as an error by VBA which is good.


The next example shows you how to specify the return type



Function PerformCalc() As Long

Function Sub

You can see this is simple to how you declare a variable. You can return any type you can declare as a variable including objects and collections.


 


A Quick Comparison

Sub: Cannot return a value


Function: Returns a value


Sub: You can run it from VBA\Button\Event etc.


Function:  You cannot run it from VBA\Button\Event etc. You can run in two ways:



Call it from another Sub/Function
When you create a Function it appears in the worksheet function list for the current workbook

 


Function: How to Return Values

To return a value from a function you assign the value to the name of the Function. The following examples demonstrates this



Function GetAmount() As Long
' Returns 55
GetAmount = 55
End Function

Function GetName() As String
' Returns John
GetName = "John"
End Function

When you return a value from a function you will obviously need to get it back to the calling Function/Sub. You do this by assigning the Function call to a variable. The following example shows this



Sub WriteValues()
Dim Amount As Long
' Get value from GetAmount function
Amount = GetAmount
End Sub

Function GetAmount() As Long
GetAmount = 55
End Function

You can easily test your return value using Debug.Print. This will write values to the Immediate Window. To view select View->Immediate Window(shortcut Ctrl + G).



Sub WriteValues()
' Print return value to Immediate Window
Debug.Print GetAmount
End Sub

Function GetAmount() As Long
GetAmount = 55
End Function

Note: When you assign the return value of a function you need to use parenthesis around the function arguments


 


Passing Arguments

Arguments are passed to Subs and Functions in the same way. One important thing to keep in mind is that if you use parenthesis when calling the Function/Sub then passing by reference(ByRef) does not work. We’ll have a look at this later in the section.


The following shows how to declare a parameter for a Sub and Function



Function CalcValue(x As Long)

End Function

Sub WriteValue(x As Long)

End Sub


You can see it is similar to creating a variable except that we don’t use Dim. You can specify two ways of passing a variable: ByRef or ByVal.



' Pass by value
Sub WriteValue1(ByVal x As Long)

End Function

' Pass by reference
Sub WriteValue2(ByRef x As Long)

End Sub

' No type used so it is ByRef
Sub WriteValue3(x As Long)

End Sub

If you don’t specify the type then ByRef is the type as you can see in the third sub of the example.


The different between these type is:

ByVal - Creates a copy of the variable you pass.

This means if you change the value of the parameter it will not be changed when you return to the calling Sub/Function


ByRef - Creates a reference of the variable you pass.

This means if you change the value of the parameter variable it will be changed when you return to the calling Sub/Function.


The following code example shows this



Sub Test()

Dim x As Long

' Pass by value - x will not change
x = 1
Debug.Print "x before ByVal is"; x
SubByVal x
Debug.Print "x after ByVal is"; x

' Pass by reference - x will change
x = 1
Debug.Print "x before ByRef is"; x
SubByRef x
Debug.Print "x after ByRef is"; x

End Sub

Sub SubByVal(ByVal x As Long)
' x WILL NOT change outside as passed ByVal
x = 99
End Sub

Sub SubByRef(ByRef x As Long)
' x WILL change outside as passed ByRef
x = 99
End Sub

The result of this is:

x before ByVal is 1

x after ByVal is 1

x before ByRef is 1

x after ByRef is 99


You should avoid passing basic variable types using ByRef. There are two main reasons for this



The person passing a value may not expect it to change and this can lead to bugs that are difficult to detect
Using parenthesis when calling prevents ByRef working – see next sub section

Therefore you should always declare your parameters as ByVal for basic types.


A Little-Known Pitfall of ByRef

There is one thing you must be careful of when using ByRef parameters. If you use  parenthesis then the Sub/Function cannot change the variable you pass even if it is passed ByRef . In the following example we call the Sub first without parenthesis and then with parenthesis. This causes the code to behave differently.



Sub Test()

Dim x As Long

' Call using without Parenthesis - x will change
x = 1
Debug.Print "x before (no parenthesis): "; x
SubByRef x
Debug.Print "x after (no parenthesis): "; x

' Call using with Parenthesis - x will not change
x = 1
Debug.Print "x before (with parenthesis): "; x
SubByRef (x)
Debug.Print "x after (with parenthesis): "; x

End Sub

Sub SubByRef(ByRef x As Long)
x = 99
End Sub

As you

So as I said in the last section you should avoid passing a variable using ByRef and instead use ByVal.


This means



The variable you pass will not be accidentally changed
Using parenthesis will not affect the behaviour

 


Custom Function vs Worksheet Function

When you create a function it appears in the function list for that workbook. Look at the function in the next example.



Sub MyNewFunction()
MyNewFunction = 99
End Sub

If you add this to a workbook then the function will appear in the function list. Type “=My” into the function box and the function will appear as shown in the following screensheet.


Worksheet Function

If you use this function in a cell you will get the result 99 in the cell as that is what the function returns.


 


Conclusion

The main points of this post are



Subs and Macros are the same thing in VBA
Use a Sub to write most of your code
Use a Function if you need to return a value
A Sub can be run in many ways
Functions must be called by a Sub/Function or used as a worksheet function
Functions appear in the workbook function list for the current workbook
ByRef allows the Function\Sub to change the original argument
If you call a Function\Sub with parenthesis then ByRef will not work

This post provided and in-depth look and functions and subs. I hope you found it beneficial. You may want to check out some of my other in-depth posts on the important elements of VBA – A Quick Guide to All the Posts


 •  0 comments  •  flag
Share on Twitter
Published on April 13, 2015 06:14

April 7, 2015

How To Start From Scratch With VBA in Excel

“The secret of getting ahead is getting started” – Mark Twain.


Start with VBA in Excel


Have you just started with VBA in Excel?


Would you like to  learn VBA  but feel it is too complex?


Are you a frequent Excel user who would love to know more about macros?


If you answered yes to any of these questions  then this post it for you.  When you finish reading it you will be able to create and run simple macros using VBA.


This posts uses Excel 2013 but is also valid for  Excel 2007/2010.


What is VBA in Excel

VBA is the programming language, Visual Basic for Applications. This language comes pre-installed with Excel. It is very powerful and allows you to extend the functionality of Excel.


You will not only find VBA in Excel, but also in any Microsoft Office application such as Microsoft Word, Access and Outlook.


Step 1 Make the Developer Tab Visible

The Developer Tab is normally visible by default on your ribbon. If not you can make it visible using the following steps


1. Right click on the ribbon. In the list that appears select “Customize the Ribbon”


Ribbon Customize


 


2. In the dialog that appears you will see a list of tabs on the right hand side. Ensure that “Developer” is checked on.


CheckDeveloper


 


Step 2 Check Your Security Setting

The next step is to ensure your Macro settings are correct. On the Developer Ribbon, Click on the “Macro Security” button under the “Code” section.


Click Macro Button


 


You security settings should match the settings in the screenshot below


 


Excel VBA


 


Step 3 Save as a Correct File Type

If you workbook has Macros then you must save it as a Macro Enabled Workbook. It is a good idea to do this in the beginning so as to avoid the potential lost of code.


Select File->Save As and choose “Macro Enabled Workbook” from the File type. Then click on Save.


VBA Macro Enabled


 


 


Step 4 Enter the Visual Basic Editor

To enter the Visual Basic editor click on the Visual Basic icon on the Developer tab of the Ribbon. Alternatively you can press Alt F11 on the keyboard


Visual Basic Icon


 


Step 5 Create a Module

Macros are stored in Modules so create a module.


Look in the VBA Project Window. If the window is not visible the select  “View” ->”Project Explorer” from the menu (shortcut Ctrl key and R).


Select the workbook where you want to place the code. The workbooks will be in parenthesis beside “VBAProject”. Each open workbook will have an entry like this in the VBA Project window


VBA Project Window.


 


Right click on the workbook where you wish to place the code. Select “Insert” and then “Module”.


CreateModule


a new module  will appear:


New Module


When you double click on a Module in the VBA Project window the code of that module is displayed in the main code window. When a new module is created it normally doesn’t contain any code(note it may contain “Option Explicit” if you have this option turned on).


MainWindow VBA


 


Step 6 Create a Macro

Type “Sub MyFirstMacro” in the main code window and press return. You should have the following


EmptyMacro


 


 


Step 7 Add Some Code to Your Macro

Use MsgBox “Hello World”. This will display a dialog with “Hello World” to the user


Sample VBA Code


 


 


Step 8 Run Your Macro

To run your macro:



Click anywhere inside the Macro
Select Run->Run Sub/UserForm 

Note: If the cursor is not inside a Macro then VBA will display a list of available Macros and ask you to select one to run.


Sample VBA Code Run


 


You should get a dialog like this


Sample VBA Code Run Dialog


 


 


Conclusion

This post showed you how to get up and running using VBA. It went through the steps for setting up correctly and ended with you running a macro.


You might like to try our other popular posts such as The Complete Guide To Workbooks in Excel VBA or click  here to view all the posts on this site by category.


Please feel free to subscribe to my newsletter and get exclusive VBA content that you cannot find here on the blog, as well as free access to my eBook, How to Ace the 21 Most Common Questions in VBA which is full of examples you can use in your own code.

Free VBA eBook


 





The post How To Start From Scratch With VBA in Excel appeared first on Excel Macro Mastery.

 •  0 comments  •  flag
Share on Twitter
Published on April 07, 2015 08:24

How To Start From Scratch With Excel VBA

“The secret of getting ahead is getting started” – Mark Twain.


Getting started with VBA


 


 


 


 


 


 


 


 


Would you like to  learn VBA  but feel it is too complex?


Are you a frequent Excel user who would love to know more about macros?


Have you just started with Excel VBA?


If you answered yet to any of these questions  then this post it for you.  When you have finished you will be able create and run simple macro using VBA.


This posts uses Excel 2013 but is also valid for  Excel 2007/2010.


Step 1 Ensure the Developer Tab is Visible

The Developer Tab is normally visible by default on your ribbon. If not you can make it visible using the following steps


1. Right click on the ribbon. In the list that appears select “Customize the Ribbon”


Ribbon Customize


 


2. In the dialog that appears you will see a list of tabs on the right hand side. Ensure that “Developer” is checked on.


CheckDeveloper


 


Step 2 Ensure Your Security Setting are Correct

The next step is to ensure your Macro settings are correct. On the Developer Ribbon, Click on the “Macro Security” button under the “Code” section.


Click Macro Button


 


You security settings should match the settings in the screenshot below


 


Excel VBA


 


Step 3 Save as a Macro Enabled Workbook

If you workbook has Macros then you must save it as a Macro Enabled Workbook. It is a good idea to do this in the beginning so as to avoid the potential lost of code.


Select File->Save As and choose “Macro Enabled Workbook” from the File type. The click on Save.


VBA Macro Enabled


 


 


Step 4 Enter the Visual Basic Environment

To enter the Visual Basic editor click on the Visual Basic icon on the Developer tab of the Ribbon. Alternatively you can press Alt + F11 on the keyboard


Visual Basic Icon


 


Step 5 Create a Module

Macros are stored in Modules so create a module.


Look in the VBA Project Window. If the window is not visible the select  “View” ->”Project Explorer” from the menu (shortcut Ctrl + R).


Select the workbook where you want to place the code. The workbooks will be in parenthesis beside “VBAProject”. Each open workbook will have an entry like this in the VBA Project window


VBA Project Window.


 


Right click on the workbook where you wish to place the code. Select “Insert” and then “Module”.


CreateModule


a new module  will appear:


New Module


When you double click on a Module in the VBA Project window the code of that module is displayed in the main code window. When a new module is created it normally doesn’t contain any code(note it may contain “Option Explicit” if you have this option turned on).


MainWindow VBA


 


Step 6 Create a Macro

Type “Sub MyFirstMacro” in the main code window and press return. You should have the following


EmptyMacro


 


 


Step 7 Add Some Code to Your Macro

Use MsgBox “Hello World”. This will display a dialog with “Hello World” to the user


Sample VBA Code


 


 


Step 8 Run Your Macro

To run your macro:



Click anywhere inside the Macro
Select Run->Run Sub/UserForm 

Note: If the cursor is not inside a Macro then VBA will display a list of available Macros and ask you to select one to run.


Sample VBA Code Run


 


You should get a dialog like this


Sample VBA Code Run Dialog


 


 


Conclusion

This post showed you how to get up and running using VBA. It went through the steps for setting up correctly and ended with you running a macro. If you found this post useful the you might like to try our other posts such as The Complete Guide To Workbooks in Excel VBA or The Complete Guide to Ranges and Cells in Excel VBA.


 


 •  0 comments  •  flag
Share on Twitter
Published on April 07, 2015 08:24

March 5, 2015

The Ultimate Guide to Loops in Excel VBA

“Nearly all men can stand adversity, but if you want to test a man’s character, give him power” – Abraham Lincoln.


http://www.dreamstime.com/stock-images-fair-rides-image6828374

© Heysues23 | Dreamstime.com – Fair Rides Photo



Introduction

Loops are by far the most powerful component of VBA. They are the rocket fuel of your Macros. They can perform tasks in milliseconds that would take humans hours. They dramatically reduce the lines of code you need.


If you have never used loops before then this post is a great place to start. The aim here is to provide you with an in-depth guide to using loops, written in plain English.


The following questions will be addressed


What are Loops?


Why you need them?


When should you use them?


How do they work?


Which one should you in a given situation?


The  first section of the post provides a quick guide to loops. If you are here looking for some quick info on loops then this is for you.


Otherwise you can skip to the second section where we start with a very important question – what are loops and why do we need them?


Quick Guide To Loops

There are 4 types of loops in VBA. The Do Loop can be used in 4 ways. The following table provides a quick guide to loops


A quick guide to loops in Excel VBA

A quick guide to loops in Excel VBA


 


What are Loops and Why Do You Need Them?

A loop is simply a way of running the same lines of code a number of times. Obviously running the same code over and over would give the same result. What is important to understand is that the lines of code normally contain a variable that changes slightly each time.


For example a loop could write to A1, then A2, A3 and so on. The slight change each time is the row.


Let’s look at a simple example.


Example 1: Printing 1 to 5

The following code  prints the values 1 to 5 in the Immediate Window.



Debug.Print 1
Debug.Print 2
Debug.Print 3
Debug.Print 4
Debug.Print 5

 


The Immediate Window

If you have not used the Immediate Window before then this section will get you up to speed quickly.


Note: The function Debug.Print writes values to the Immediate  Window. To view this window select View->Immediate Window from the menu( Shortcut is Ctrl + G)


ImmediateWindow


 


ImmediateSampeText


Example 2: Printing  1 to 20

Now imagine we want to print out the numbers 1 to 20. We would need to add 15 more lines using the same code. However using a loop we only need to write Debug.Print once.



For i = 1 To 20
Debug.Print i
Next i

The output is


VBA Excel

Output


If we needed print the numbers 1 to 1000 then we only need to change the 20 to 1000. Normally in code you would use a variable instead of the values 20 or 1000. This gives you greater flexibility. It allows you to decide the number of times you wish to run the loop when the Macro runs. The following example explains this.


Example 3: Counting Fruit Sold

A common task in Excel is read to the last row of a sheet with data. So the way you would do this is by first finding the last row with data and then using the number of this row in the loop. Then if more lines of data are added the code will still work fine.


Let’s have a look how you would do this with code. Imagine you receive a sheet with a list of fruit types that have been sold each day. You want to count the number of Oranges sold and this list will vary in size depending on sales. The following screenshot shows an example of this list


Sample Data of Fruit Sales

Sample Data of Fruit Sales


We can use the code to count the oranges



Sub CountFruit()

' Get the last row with text
Dim LastRow As Long
LastRow = Cells(Rows.Count, 1).End(xlUp).Row

Dim i As Long, Total As Long
' Use LastRow in loop
For i = 2 To LastRow
' Check if cell has text "Orange"
If Cells(i, 1).Value = "Oranges" Then
' Add value in column B to total
Total = Total + Cells(i, 2).Value
End If
Next i

' Print total
Debug.Print "Total oranges sold was:"; Total

End Sub

You can try this code for yourself. Change the number of fruit items and you will see that the code still works fine.


If you were to increase the number fruit items to a large value like 10,000 then you hardly notice the difference in the time it takes to run – almost instantly. Loops are super fast. This is what makes them so powerful. Imagine performing a manual task on 10,000 cells. It would take a considerable amount of time.


You may be thinking that excel functions like Sum and Count are powerful as they can also perform a task with a large number of cells quickly. This is true but if you looked at the original code of the function you would find it contains a loop.


Advantages

To conclude this section we will list the major advantages of using loops



They reduce the lines code you need
They are flexible
They are fast

In the next sections we will look at the different types of loops and how to use them.


The For Loop

In VBA the For loop is the most common loop you will use. The For Loop is used when you can determine the number of times it will be run. For example if you want to repeat something twenty times.


Format of the Loop

A for loop is constructed as follows


For = to

Next


The start and end values can be variables. Also the variable after Next is optional but it is useful and it makes it clear which for loop it belongs to.


How a Loop Works

Let’s look at a simple for loop that prints the numbers 1 to 3



Dim i As Long
For i = 1 To 3
Debug.Print i
Next i

How this code works is as follows


i is set to 1

The value of i(now 1) is printed

i is set to 2

The value of i(now 2) is printed

i is set to 3

The value of i(now 3) is printed


If we did not use a loop then the equivalent code would be



Dim i As Long
i = i + 1
Debug.Print i
i = i + 1
Debug.Print i
i = i + 1
Debug.Print i

The “i = i + 1″ line is used to add 1 to i and is a common way in programming to update a counter.


Using Step

You can see that i is increased by one each time. This is the default. You can specify this interval using Step. The next example shows you how to do this



' Prints the even numbers i.e. 2,4,6,8 ... 20
For i = 2 To 20 Step 2
Debug.Print i
Next i

You can use a negative number with Step which will count in reverse



' Prints the even numbers in reverse i.e. 20,18,16,14 ... 2
For i = 20 To 2 Step -2
Debug.Print i
Next i

Note if Step is positive then your starting number must be lower than you ending number. The following loop will not run because the starting number 20 tells VBA it has already reached the target value 10.



' Will not run as starting number already greater than 10
For i = 20 To 10 Step 1
Debug.Print i
Next i

If Step is negative then the start number must be greater than the end number.


Exit For

Sometimes you may want to leave the loop earlier if a certain condition occurs. For example if you read bad data. You can use Exit For to automatically leave  the loop as shown in the following code



For i = 1 To 1000

' If cell is blank then exit for
If Cells(i, 1) = "" Then
MsgBox "Blank Cell found - Data error"
Exit For
Else
Debug.Print Cells(i, 1)
End If

Next i

 


Using For with a Collection

The for loop can also be used to read items in a collection. In the following example we display the name of all the open workbooks



Dim i As Long
For i = 1 To Workbooks.Count
Debug.Print Workbooks(i).FullName
Next i

 


Using a Loop with a Loop

Sometimes you may want to use a loop within a loop. An example of this would be where you you want to print the names of the worksheets of each open workbook.


The first loop would go through each workbook. Each time this loop runs it would use a second loop to go through all the worksheets of that workbook. It is actually much easier to do than it sounds. The following code shows how



Sub ListWorksheets()

Dim i As Long, j As Long
' First Loop goes through all workbooks
For i = 1 To Workbooks.Count

' Second loop goes through all the worksheets of workbook(i)
For j = 1 To Workbooks(i).Worksheets.Count
Debug.Print Workbooks(i).Name + ":" + Worksheets(i).Name
Next j

Next i

End Sub

This works as follows

The first loop set i to 1

The second loop then uses the workbook at 1 to go through the worksheets.

The first loop sets i to 2

The second loop then uses the workbook at 2 to go through the worksheets.

and so on


It the next section we will use a For Each loop to perform the same task. You will find the For Each version much easier to read.


The For Each Loop

The For Each loop is used to read items from a collection or an array. We can can use the For Each loop to access all the open workbooks



Dim wk As Workbook
For Each wk In Workbooks
Debug.Print wk.FullName
Next wk

 


 Format of the For Each Loop

For Each  in

Next


To create a For Each loop we need a variable of the same type that the collection holds. In the example here we created a variable of type Workbook. If the collection has different types of items we can declare the variable as a variant.


VBA contains a collection called Sheets. This is a collection of sheets of type Worksheet(normal) and Chart(when you move a chart to be a full sheet). To go through this you would declare the variable as a variant. The following code used For Each to print out the name of all the sheets in the current workbook



Dim sh As Variant
For Each sh In ThisWorkbook.Sheets
Debug.Print sh.Name
Next sh

 


Order of Items

For Each goes through items in one way only. For example if you go through all the worksheets in a workbook it will always go through from left to right. If you go through a range it will start at the lowest cell e.g. Range(A1:A10) will return A1,A2,A3 etc. This means if you want any other order then you need to use the For loop.


Both loops in the following will read the worksheets from left to right.



' Both loops read the worksheets from left to right
Dim wk As Worksheet
For Each wk In ThisWorkbook.Worksheets
Debug.Print wk.Name
Next

Dim i As Long
For i = 1 To ThisWorkbook.Worksheets.Count
Debug.Print ThisWorkbook.Worksheets(i).Name
Next

As you can see the For Each loop is neater to write. However if you want to read the sheets in any other order e.g. right to left then you have to use the for loop.



' Reading the worksheets from right to left
Dim i As Long
For i = ThisWorkbook.Worksheets.Count To 1 Step -1
Debug.Print ThisWorkbook.Worksheets(i).Name
Next

 


 For Each is Read-Only

Another attribute of the For Each loop is that it is Read-Only. You cannot change the value. The following example demonstrates this



Sub UseForEach()

' Create array and add three values
Dim arr() As Variant
arr = Array("A", "B", "C")

Dim s As Variant
' Assigning s does not change the array item
For Each s In arr
' Changes what s is referring to - not value of array item
s = "Z"
Next

' Print items to show the array has remained unchanged
For Each s In arr
Debug.Print s
Next

End Sub

In the first loop we try to assign s to “Z”. When happens is that s is now referring the string “Z” and no longer to the item in the array.

In the second loop we print out the array and you can see that none of the values have changes.


When we use the For Loop we can change the array item. If we change the previous code to use the For Loop you it will change all the array values to “Z”



Sub UsingForWithArray()

' Create array and add three values
Dim arr() As Variant
arr = Array("A", "B", "C")

Dim i As Long
For i = LBound(arr) To UBound(arr)
' Changes value at position to Z
arr(i) = "Z"
Next

' Print items to show the array values have change
For i = LBound(arr) To UBound(arr)
Debug.Print arr(i)
Next

End Sub

 


Which is Faster? For vs For Each

The For Each loop is widely considered faster than the For loop as it is. However I have been unable to find any concrete sources to back this up 100%. What is important to remember when considering speed is that



The processing power of modern computers means both loops work extremely fast.
You need to have a huge collection for speed to be an issue

Therefore most of the time the loop speed difference will not be an issue for you. If it is then the best thing to do is to try both loops and see which is faster.


Loop Within a Loop

We saw already that you can have a loop inside other loops. In our previous example we used For to read all the worksheets in all the open workbooks. This time we will use For Each to perform the same task



Sub ReadAllWorksheets()

Dim wk As Workbook, sh As Worksheet
' Read each workbook
For Each wk In Workbooks

' Read each worksheet in the wk workbook
For Each sh In wk.Worksheets
' Print workbook name and worksheet name
Debug.Print wk.Name + ": " + sh.Name
Next sh

Next wk

End Sub

As you can see this is a neater way of performing this task than using the For Loop.


This code run as follows:



Get the first Workbook from the Workbooks collection
Go through all the worksheets in this workbook
Print the workbook/worksheet details
Get the next workbooks in the collection
Repeat steps 2 to 3
Continue until no more workbooks are left in the collection

 


The next loop we will look at is the Do loop. This uses a condition to determine when it completes so first we will take a quick look at conditions.


Conditions

A condition is a statement that evaluates to true or false. They are mostly used with Loops and If statements. When you create a condition you use signs like >,<>,>=,=.


The following are examples of conditions


VBA Conditions

VBA Conditions


 


You may have noticed x=5 as a condition. This should not be confused with x=5 when used as an assignment. When equals is used in a condition it means “is the left equal to the right”. The following table demonstrates how equals is used in conditions and assignments


Use equals in a condition

Use equals in a condition vs statement


 


The Do Loop

The Do loop can be used in four ways and so often causes confusion. There is only a slight difference in each of these four ways.


The difference between the For loop and this loop is that For loop specifies the number of times it will run. The other loops run until a condition is met.


A Do Loop Example

Lets look at a simple example to explain this. Imagine you want to get a series of items from the user. Each time the user enters an item you print it to the immediate window. When the user enters a blank string the macro terminates.


In this case the For loop would not be suitable as you do not know how many items the user will enter. The user could enter the blank string first or hundredth time. For this type of situation you would use a Do loop. The following code shows an example of this




Dim sCommand As String

Do
' Get user input
sCommand = InputBox("Please enter item")

' Print to Immediate Window(Ctrl G to view)
Debug.Print sCommand

Loop Until sCommand = ""


The code enters the loop and runs the code. When it reaches the “Loop Until” line it checks the condition



sCommand = ""

If the condition is true then it exits the loop. If the condition is false it returns to the start of the loop.


Do Loop Until Format

The format of this loop is


Do

Loop Until


You can also place the condition at the start of the loop


Do Until

Loop


The different between these two loops is that  the first will run 1 or more times and the second will run 0 or more times. In other words the first will run once before checking the condition so it will always run at least once.


In our example the first loop was used because we need to get a value from the user before we check it. In the following example we use both versions of the loop. The loop will run until the user enters the letter ‘n’



Sub GetInput()

Dim sCommand As String

' Condition at start
Do Until sCommand = "n"
sCommand = InputBox("Please enter item for Loop 1")
Loop

' Condition at end
Do
sCommand = InputBox("Please enter item for Loop 2")
Loop Until sCommand = "n"

End Sub

In this case both loops will behave the same. However if sCommand is equal to ‘n’ before the Do Until loop it will never run. The Do loop will always run at least once.




Sub GetInput2()

Dim sCommand As String
sCommand = "n"

' Loop will not run as command is "n"
Do Until sCommand = "n"
sCommand = InputBox("Please enter item for Loop 1")
Loop

' Loop will still run at least once
Do
sCommand = InputBox("Please enter item for Loop 2")
Loop Until sCommand = "n"

End Sub


 


Using While instead of Until

You can use While instead of Until in the do loop. This is the same as using Until except for one slight difference – While uses the opposite condition. Until and While are used the same as they are used in English. For example



Leave the clothes on the line Until it rains
Leave the clothes on the line While it does not rain

another example



Stay in bed Until it is light
Stay in bed While it is dark

yet another example



repeat Until the count equals ten
repeat While the count count is less than ten

As you can see – using Until and While is just the opposite way of writing the same condition.


The Do While Loop Format

The only difference in the format of the loop is that you replace Until with While.


Do

Loop While 


Do While

Loop


The following code shows the ‘While’ and ‘Until’ loops side by side. As you can see the only difference is the condition is reversed. Note that ‘<>’ means ‘does not equal’.




Sub GetInput()

Dim sCommand As String

' Condition at start
Do Until sCommand = "n"
sCommand = InputBox("Please enter item for Loop 1")
Loop

Do While sCommand <> "n"
sCommand = InputBox("Please enter item for Loop 1")
Loop

' Condition at end
Do
sCommand = InputBox("Please enter item for Loop 2")
Loop Until sCommand = "n"

Do
sCommand = InputBox("Please enter item for Loop 2")
Loop While sCommand <> "n"

End Sub


The first loop says Loop until sCommand equals ‘n’. The second loop says loop while sCommand does not equal ‘n’.


Example: Checking Objects

An example of where Until and While are useful is for checking objects. When an object has not been assigned it has the value Nothing. So when we declare workbook in the following example it has a value of nothing until we assign it to a workbook



Dim wrk As Workbook

The opposite of “Nothing” is “Not Nothing” which can be confusing. Take the following example. Imagine we have two functions called GetFirstWorkbook and GetNextWorkbook which return some workbook objects. The code will print the name of the workbook until the functions do not return a workbook. You can see the sample code here




Dim wrk As Workbook
Set wrk = GetFirstWorkbook()

Do Until wrk Is Nothing
Debug.Print wrk.Name
Set wrk = GetNextWorkbook()
Loop

To write this code using Do While would be more confusing as the condition is Not Is Nothing




Dim wrk As Workbook
Set wrk = GetFirstWorkbook()

Do While Not wrk Is Nothing
Debug.Print wrk.Name
Set wrk = GetNextWorkbook()
Loop


This makes the code clearer and having clear conditions is always a good thing. To be honest this is a very small difference and choosing between While and Until really comes down to a personal choice.


While Wend

This loop is in VBA to make it compatible with older code. Microsoft recommends that you use the Do loops as they are more structured.


From MSDN: “The Do…Loop statement provides a more structured and flexible way to perform looping.”


Format of the While Wend Loop

The While loop has the following format


While 

Wend


While Wend vs Do

The different between While and the Do Loop is :


1. While can only have a condition at the start of the loop


2. There is not statement to exit a While loop like Exit For or Exit Do


The condition for the While loop is the same as for the Do While loop. The two loops in the code below perform exactly the same way




Sub GetInput()

Dim sCommand As String

Do While sCommand <> "n"
sCommand = InputBox("Please enter item for Loop 1")
Loop

While sCommand <> "n"
sCommand = InputBox("Please enter item for Loop 2")
Wend

End Sub


 


 Infinite Loop

Even if you have never written code in your life I’m sure you’ve heard the phrase Infinite Loop. This is a loop where the condition will never be met. It normally happens when you forget to update the count.


The following code shows an infinite loop




Dim cnt As Long
cnt = 1

' Do not run - this is an infinite loop
Do While cnt < 5

Loop


In this example cnt is set to 1 but it is never updated. Therefore the condition will never be met – cnt will always be less than 5.


In the following code the cnt is being updated each time so the condition will be met.




Dim cnt As Long
cnt = 1

Do While cnt < 5
cnt = cnt + 1
Loop


As you can see using a For Loop is safer for counting as it automatically updates the count in a loop. The following is the same loop using For.




Dim i As Long
For i = 1 To 4

Next i


This is clearly a better way of doing it. The For Loop sets the initial value, condition and count in one line.


Of course it is possible to have an infinite loop using For – It just takes a bit more effort :-)




Dim i As Long
' DO NOT RUN - Infinite Loop
For i = 1 To 4
' i will never each 4
i = 1
Next i


 


Dealing With an Infinite Loop

When you have an infinite loop – VBA will not give an error. You code will keep running and the Visual Basic editor will not respond.


In the old days you could break out of a loop by simply pressing Ctrl and Break. Nowadays different Laptops use different key combinations for the same result. It is a good idea to know what this is for your laptop so that if an infinite loop occurs you can stop the code easily.


You can also break out of a loop by killing the process. Press Ctrl+Shift+Esc. Under the Processes tab look for Excel/Microsoft Excel. Right click on this and select “End Process”. This will close Excel and you may lose some work – so it’s much better to use Ctrl+Break or it’s equivalent.


 


Using Worksheet Functions Instead of Loops

Sometimes you can use a worksheet function instead of using a loop. For example, imagine you wanted to add the values in a list of cells. You could do this using a loop but it would be more efficient to use the worksheet function Sum. This is quicker and saves you a lot of code.


It is very easy to use the Worksheet functions. The following is an example of using Sum and Count. Remember that in VBA the argument they take is a range object and not a string. In other words you must use Range(“A1:A10″) rather than “A1:A10″.




Sub WorksheetFunctions()

Debug.Print WorksheetFunction.Sum(Range("A1:A10"))

Debug.Print WorksheetFunction.Count(Range("A1:A10"))

End Sub


The following examples uses a loop to perform the same action. As you can see it is a much longer way of achieving the same goal




Sub SumWithLoop()

Dim total As Long, count As Long
Dim rg As Range
For Each rg In Range("A1:A10")
' Total
total = total + rg
' Count
If rg <> "" Then
count = count + 1
End If
Next rg

Debug.Print total
Debug.Print count

End Sub


 


Summary

There are four types of loops in VBA:

For Next
For Each Next
Do Loop
While Wend


 The For Loop is the most commonly used in VBA
The For loop is flexible as you can determine the size and order to read through.
The For Each is used to read through a collection. You cannot change the order. It is neater to write than a For Loop.
For Each is considered faster than the For Loop but with modern processing power this not  an issue unless you have extremely large collections.
For Each is read only – you cannot change the value of the item
For can read and write – you can change the value of the item
The While Wend loop is obsolete and you can use the Do Loop instead.
The Do loop can be used 4 ways. With a While/Until condition at the start or end of the loop.
While and Until use opposite conditions in a Do loop.
Infinite Loops occur if your loop condition will never be met
Sometimes using a worksheet function is more efficient than using a loop

 


I hope you enjoyed this post and found it beneficial. You may also find the posts about Arrays or Cells very useful.


 •  0 comments  •  flag
Share on Twitter
Published on March 05, 2015 00:41