VBA comes with a large number of built-in functions that perform commonly needed operations—everything from determining whether a file exists on the hard drive to returning the current date or converting data from one format to another. For example, there's a function that converts numeric data into a text string.
In this book, I usually refer to most VBA language components (VBA's diction) as commands. In this chapter, though, we'll call them functions. Other names that are sometimes used—more or less accurately—for these built-in commands include: operations, methods (with objects), routines, procedures, and stored procedures.
This chapter demonstrates what functions are, what they do, and how to use them. Along the way, you'll get to know some of the key functions built into VBA—including functions that manage file operations, functions that do math, that manipulate strings, and many others.
You can also create custom functions of your own to supplement VBA's built-in functions. The next chapter tells you how to build your own when VBA's functions don't meet your special needs.
A function, like a subroutine, is a type of procedure. In the BASIC language (of which VBA is a descendant), a function differs from a sub (subroutine) in that a function always returns a value. A subroutine doesn't.
And in common practice, a function almost always takes one or more arguments. Although subroutines can be written to take arguments, most programmers don't write their code that way.
Other computer languages don't make a distinction between function and subroutine. So, to sum up, here are the key differences between functions and subroutines in VBA:
Many functions are pre-written by Microsoft and already exist within the VBA language for you to use. These are called built-in functions. Usually you send them some information, and get data back. To see one example, the built-in IsDate function gets a date and sends back True or False. Here it gets the date May, 2019 and sends back True if it's currently May, 2019. It sends False if not.
Dim s As String
s = IsDate("05/19")
MsgBox s
You'll often use built-in VBA functions like this. Typically, you feed information into a built-in function by sending it arguments. The built-in function then processes that info and sends (returns) a value for you to use in your code.
Built-in functions are so pervasive that you've already used several in examples in this book. However, we'll now explore them more fully. For example, in Chapter 7, “Using Array Variables,” you used the
function to generate random numbers to fill an array named Rnd
, and the intArray
function to turn the random numbers into integers:Int
intArray(i) = Int(Rnd * 10)
is one of the rare functions that does not have to be fed one or more arguments. (Rnd
can take one optional argument, but the previous example doesn't use it.)Rnd
The
function, on the other hand, requires an argument—the number or expression that you want turned into an integer. The argument in this example is supplied by the expression Int
. Here the Rnd * 10
function returns a value that the Rnd
function uses. The Int
function then returns a value to the procedure, which uses it to populate a subscript in the array.Int
Note that argument is a piece of information that gets passed to a function. (Arguments are also passed to objects' methods and other commands.) You can tell when arguments are optional in Help descriptions because they're shown enclosed within brackets. When they are optional, you can choose to either provide or omit the arguments displayed in the brackets. For example, the full Help syntax for the
function looks like this:Rnd
Rnd([number]) As Single
The brackets indicate that the
argument is optional, and the number
part of the syntax denotes that the value returned by the function will be of the Single data type.As Single
Different functions return different data types suited to their jobs: Many functions return a Variant, but yes/no functions, such as the
function used in Chapter 7, or the IsNumeric
function we just used, return a Boolean value, either IsDate
or True
. When necessary, VBA may even sometimes convert the result of a function to a different data type needed by another function in the expression.False
If any pair of brackets contains two arguments, you have to use both of them at once (blessedly, this is quite rare). For example, the
function displays a message box. The syntax for the MsgBox
function is as follows:MsgBox
MsgBox(prompt[, buttons] [, title][, helpfile, context])
Here,
is the only required argument: prompt
, buttons
, title
, and helpfile
are all optional; they're bracketed. But notice that context
and helpfile
are enclosed within a single set of brackets instead of each having its own pair, meaning that you need to use either both of these arguments or neither of them. You cannot use one without the other. Chapter 13, “Getting User Input with Message Boxes and Input Boxes,” shows you how to use the context
function in your code.MsgBox
To use a function, you call (execute) it from elsewhere in your code.
To call a function, you can use a
statement, either with the optional Call
keyword or by just using the name of the function. Using the Call
keyword allows you to search through all calls in your project by searching for “call ” (call followed by a space). However, using the Call
keyword is overkill for everyday functions. Programmers rarely use it.Call
The syntax for the
statement is as follows:Call
[Call] name [argumentlist]
Here,
is a required String argument giving the name of the function or procedure to call, and name
is an optional argument providing a comma-delimited list of the variables, arrays, or expressions to pass to the function or procedure. Remember that when calling a function, you'll almost always need to pass arguments to it (except for those few functions that take no arguments).argumentlist
The brackets around the
keyword indicate that it is optional. If you do use this keyword, you need to enclose the Call
argument in parentheses. In most cases, it's easier to read the code if you don't use the argumentlist
keyword when calling a function.Call
For example, the following statement calls the
function, supplying the required argument MsgBox
(in this example, it's the string prompt
):Hello, World!
MsgBox "Hello, World!"
You could use the
keyword instead, as shown in the following statement, but there's little advantage in doing so:Call
Call MsgBox "Hello, World!"
(Note that the
function is one of the few with which you can omit the parentheses around the argument list.)MsgBox
You can assign to a variable the result returned by a function. For example, consider the following code fragment. The first two of the following statements declare the String variables
and strExample
. The third statement assigns a string of text to strLeft10
. The fourth statement uses the strExample
function to return the leftmost 10 characters from Left
and assign them to strExample
, which the fifth statement then displays in a message box (see Figure 9.1):strLeft10
Dim strExample As String
Dim strLeft10 As String
strExample = "Technology is interesting."
strLeft10 = Left(strExample, 10)
MsgBox strLeft10
If you prefer, you can assign the result of a function to a variable, as in this next example. Here the first String variable,
, is assigned the leftmost 13 characters from the string str1
. So after its code line executes, This is Pride and Patriotism
holds the value str1
. Then This is Pride
is assigned the rightmost five characters from str2
, resulting in str1
:Pride
Dim str1 As String
Dim str2 As String
str1 = Left("This is Pride and Patriotism", 13)
str2 = Right(str1, 5)
MsgBox str2
However, after you become accustomed to working with functions, you can collapse them in various ways in your code. Instead of assigning the result of a function to a variable, you can insert it directly in your code or pass it (as an argument) to another function. This is a common shortcut. Take a look at the following statement. It does the same thing as the previous example but collapses the code into one line, avoiding the use of variables altogether:
MsgBox Right(Left("This is Pride and Patriotism", 13), 5)
This statement uses three functions: the
function, the MsgBox
function, and the Left
function. (The Right
function is the counterpart of the Right
function and returns the specified number of characters from the right side of the specified string.)Left
When you have multiple sets of parentheses in a VBA statement, the code is executed starting from the innermost pair of parentheses and working outward. This is the same way that nested parentheses are handled in math.
Therefore, in the previous example the
function is evaluated first, returning the leftmost 13 characters in the string: Left
(the spaces are characters too). VBA passes this new string to the This is Pride
function, which in this case returns the rightmost five characters from it: Right
. VBA then passes this second new string to the Pride
function, which displays it in a message box.MsgBox
When a function takes more than one argument, you can pass the arguments to it in any of three ways:
The first method, supplying the arguments positionally without using their names, is usually the quickest way to proceed. The only disadvantage to doing so is that someone reading your code might not know immediately which value corresponds to which argument—although they can look this up without trouble. To omit an optional argument, you place a comma where it would appear in the sequence of arguments.
It does take extra time to type in argument names, but it makes your code easier to read. And when you omit an argument from a named argument list, you don't need to use the comma to indicate that you're skipping it.
There's no advantage to using named arguments out of order over using them in order unless you happen to find doing so easier.
For example, the
function returns a Variant/Date containing the date for the given year, month, and day. The syntax for DateSerial
is as follows:DateSerial
DateSerial(year, month, day)
Here,
, year
, and month
are all required Integer arguments.day
The following statement supplies the arguments positionally without their names:
MsgBox DateSerial(2019, 12, 31)
This next statement is equivalent but supplies the arguments positionally with their names:
MsgBox DateSerial(Year:=2019, Month:=12, Day:=31)
To illustrate the third alternative, the following statement supplies the arguments, with their names, out of order:
MsgBox DateSerial(Day:=31, Year:=2016, Month:=12)
All three of these statements work fine and achieve the same result. You'll cause a problem only if you list out-of-order arguments that you're supplying without names (positionally), if you name some arguments and don't name others, or if you omit required arguments. Figure 9.2 shows one of the errors you may encounter. In this case, I left out the required
argument.month
In VBA you don't often have to convert data types, but you might as well at least understand what it does. Some computer languages are pretty strict about requiring explicit data typing (sometimes called strong data typing). And there are a few specialized situations even in VBA where you will need to forcibly convert one variable type into another.
Say that you're using the
command to get some information from the user. The user is typing on a keyboard, so all the data they input will be characters (text string) data. But if your macro needs to do any math with this input, such as using the InputBox
command to add numbers, you would first want to convert the string data into numeric variables (or use the default Variant type). To convert a string to an integer number, you could use the +
command. This same issue arises if you are importing data from another source, such as a database that stores everything as a String variable.Cint
VBA provides a full set of simple functions for converting data from one data type to another. Table 9.1 lists VBA's functions for simple data conversion.
TABLE 9.1: VBA's functions for simple data conversion
FUNCTION (ARGUMENTS) | DATA TYPE RETURNED |
|
Boolean |
|
Byte |
|
Currency |
|
Date |
|
Decimal |
|
Double |
|
Integer |
|
Long |
|
Single |
|
String |
|
Variant |
For example, the following statements declare the untyped variable
and the Integer variable varMyInput
and then display an input box prompting the user to enter an integer. In the third statement, the user's input is assigned to intMyVar
, which automatically becomes a Variant/String. The fourth statement uses the varMyInput
function to convert CInt
to an integer, assigning the result to varMyInput
. The fifth statement compares intMyVar
to intMyVar
, converts the result to Boolean by using the 10
function, and displays the result (CBool
or True
) in a message box:False
Dim varMyInput
Dim intMyVar As Integer
varMyInput = InputBox("Enter an integer:", "10 Is True, Other Numbers Are False")
intMyVar = CInt(varMyInput)
MsgBox CBool(intMyVar = 10)
Recall that a Boolean variable is either
or True
. So, in the final line of this example, you're saying in effect, “If the value in the variable False
is 10, the Boolean result will be intMyVar
. If the value is anything other than 10, the result will be True
.”False
VBA also has a set of functions that manipulate data in more complicated ways. Only two of these more complex manipulation functions—
and Format
—are used much in VBA programming, so we'll explore them in depth in this chapter.Chr
Table 9.2 lists VBA's functions for more complex data manipulation.
TABLE 9.2: VBA's functions for complex data conversion
FUNCTION (ARGUMENTS) | RETURNS |
|
The ANSI character code for the first character in the string. |
|
The string for the specified character code (a number between 0 and 255). |
|
A Variant containing formatted as specified by . (You'll see how works in “Using the Function to Format an Expression” later in the chapter.) |
|
A string containing the hexadecimal value of . |
|
A string containing the octal value of . |
, , |
A Long integer representing the color value specified by , , and . |
|
A Long integer containing the RGB value for the specified color. |
|
A Variant/String containing a string representation of . Use the superior function instead. |
|
The numeric portion of ; if does not have a numeric portion, returns 0. Use the superior function instead. |
This function isn't used much.
tells you which numeric value has been assigned to a particular letter according to the ANSI character code that's used in Windows. A character code is a list of numbers by which computers refer to letters of the alphabet. For example, the character code used in Windows for a capital A is 65 and for a capital B is 66; a lowercase a is 97, and a lowercase b is 98.Asc
The syntax for the
function is straightforward:Asc
Asc(string)
Here,
is any string expression. For example, string
returns 65.Asc("A")
The following statements use the
function to return the character code for the first character of the current selection in the active document and display that code in a message box:Asc
strThisCharacter = Asc(Selection.Text)
MsgBox strThisCharacter, vbOKOnly, "Character Code"
The Val
function, like Asc
, is not used much, but for completeness, I've included it. The Val
function converts the numbers contained in a text string into a numeric value. Val
follows these rules:
This means that if you feed
a string consisting of tabbed columns of numbers, such as the second line here, it will read them as a single number (in this case, 445634.994711):Val
Item# Price Available On Order Ordered
4456 34.99 4 7 11
If, however, you feed it something containing a mix of numbers and letters,
will read only the numbers and strings recognized as numeric expressions (for example, Val
returns 400000 because it reads the expression as exponentiation). For example, if fed the address shown in the next example, Val("4E5")
returns 8661, ignoring the other numbers in the string (because it stops at the L of Laurel, the first character that isn't a number, a tab, a line feed, or a space):Val
8661 Laurel Avenue Suite 3806, Oakland, CA 94610
The syntax for
is straightforward:Val
Val(string)
Here,
is a required argument consisting of any string expression.string
The following statement uses
to return the numeric variable Val
from the string StreetNumber
:Address1
StreetNumber = Val(Address1)
Just as you can use
to convert a text string into a numeric value as described in the previous section, you can go the other way: convert a numeric value to a string with the CInt
function. But you should use the newer Str
function rather than the now deprecated CStr
function, for the same reasons that Str
is superior to the older CInt
command.Val
You'll need to convert a number to a string when you want to concatenate the information contained in a value with a string. Concatenation means appending one string to another, as in
, which results in the text "123" & "654"
. This result as you can see is quite distinct from adding these two numbers together mathematically."123654"
Concatenation cannot be accomplished by simply using the
operator because VBA would attempt to perform the mathematical operation addition rather than the string operation you want: concatenation.+
A text string is just that: text. It's one or more alphanumeric characters, such as “55”—and that's quite different from the number 55. You can't concatenate “55” and 55. They're not the same kind of data at all.
Here's an example. Suppose you've declared a String variable named
and a numeric variable named strYourAge
. You can't use a intAge
strYourAge
+
statement to concatenate them because they're different data types. You first need to create a string from the intAge
variable and then concatenate that string with the intAge
string. (Alternatively, you can use the strYourAge
operator to concatenate the two variables.)&
To convert a value to a string, use the
function. The syntax for the CInt
function is this:CInt
CInt(number)
Here,
is a variable containing a numeric expression (such as an Integer data type, a Long data type, or a Double data type).number
The following short procedure provides an example of converting a value to a string:
Sub Age()
Dim intAge As Integer, strYourAge As String
intAge = InputBox("Enter your age:", "Age")
strYourAge = "Your age is " & CInt(intAge) & "."
MsgBox strYourAge, vbOKOnly + vbInformation, "Age"
End Sub
The
function is a powerful tool for changing numbers, dates and times, and strings into a format that you prefer.Format
The syntax for the
function is as follows:Format
Format(expression[, format[, firstdayofweek[, firstweekofyear]]])
These are the components of the syntax:
expression
is any valid expression.format
is an optional argument specifying a named format expression or a user-defined format expression. More on this in a moment.firstdayofweek
is an optional constant specifying the day that starts the week (for date information): The default setting is vbSunday
(1
), but you can also set vbMonday
(2
), vbTuesday
(3
), vbWednesday
(4
), vbThursday
(5
), vbFriday
(6
), vbSaturday
(7
), or vb UseSystem
(0
; uses the system setting).firstweekofyear
is an optional constant specifying the week considered first in the year (again, for date information), as shown in Table 9.3.TABLE 9.3: Constants that specify how a year starts
CONSTANT | VALUE | YEAR STARTS WITH WEEK |
|
|
Use the system setting. |
|
|
The week in which January 1 falls (the default setting). |
|
|
The first week with a minimum of four days in the year. |
|
|
The first full week (seven days) of the year. |
You can define your own formats for the
function as described in the following sections if none of the predefined numeric formats (described next) suit your needs.Format
Table 9.4 lists the predefined numeric formats that you can use with the
function.Format
TABLE 9.4: Predefined numeric formats
FORMAT NAME | EXPLANATION | EXAMPLE |
General Number | The number is displayed with no thousand separator. | |
Currency | The number is displayed with two decimal places, a thousand separator, and the currency symbol appropriate to the system locale. | |
Fixed | The number is displayed with two decimal places and at least one integer place. | |
Standard | The number is displayed with two decimal places, at least one integer place, and a thousand separator (when needed). | |
Percent | The number is displayed multiplied by 100, with two decimal places and with a percent sign. | |
Scientific | The number is displayed in scientific notation. | |
Yes/No | A nonzero number is displayed as ; a zero number is displayed as . |
|
True/False | A nonzero number is displayed as ; a zero number is displayed as . |
|
On/Off | A nonzero number is displayed as ; a zero number is displayed as . |
|
For example, the following statement returns $123.45:
Format("12345", "Currency")
If none of the predefined numeric formats suit your needs, you can create your own numeric formats by using your choice of a combination of the characters listed in Table 9.5.
TABLE 9.5: Characters for creating your own number formats
CHARACTER | EXPLANATION |
|
Displays the number without any formatting. (You won't usually want to use this option.) |
0 | Placeholder for a digit. If there's no digit, VBA displays a zero. If the number has fewer digits then you use zeros, VBA displays leading or trailing zeros as appropriate. |
# | Placeholder for a digit. If there's no digit, VBA displays nothing. |
. | Placeholder for a decimal. Indicates where the decimal separator should fall. The decimal separator varies by locale (for example, a decimal point in the United States, a comma in Germany). |
% | Placeholder for a percent character. VBA inserts the percent character and multiplies the expression by 100. |
, | Thousand separator (depending on locale, a comma or a period). |
: | Time separator (typically a colon, but again this depends on the locale). |
/ | Date separator (again, what you'll see depends on the locale). |
|
Scientific format: or places a minus sign next to negative exponents. or places a minus sign next to negative exponents and places a plus sign next to positive exponents. |
− + $ ( ) | Displays a literal character. |
|
Displays the literal character. |
|
Displays the literal character. Use (the character code for double quotation marks) to provide the double quotation marks. |
For example, the following statement returns a currency formatted with four decimal places:
Format("123456", "$00.0000")
Similarly, you can create your own date and time formats by mixing and matching the characters listed in Table 9.6.
TABLE 9.6: Characters for creating your own date and time formats
CHARACTER | EXPLANATION |
|
Time separator (typically a colon, but this depends on the locale). |
|
Date separator (also locale-dependent). |
|
Displays the date (if there is a date or an integer value) in the system's short date format and the time (if there is a date or a fractional value) in the system's default time format. |
|
Displays the date (1 to 31) without a leading zero for single-digit numbers. |
|
Displays the date with a leading zero for single-digit numbers (01 to 31). |
|
Displays the day as a three-letter abbreviation (Sun, Mon, Tue, Wed, Thu, Fri, Sat) with no period. |
|
Displays the full name of the day. |
|
Displays the complete date (day, month, and year) in the system's short date format. |
|
Displays the complete date (day, month, and year) in the system's long date format. |
|
Displays the full, localized name of the day. |
|
Displays an integer from 1 (Sunday) to 7 (Monday) containing the day of the week. |
|
Displays an integer from 1 to 54 giving the number of the week in the year. The number of weeks is 54 rather than 52 because most years start and end with partial weeks rather than having 52 start-to-finish weeks. |
|
Displays an integer from 1 to 12 giving the number of the month without a leading zero on single-digit months. When used after , returns minutes instead of months. |
|
Displays a number from 01 to 12 giving the two-digit number of the month. When used after , returns minutes instead of months. |
|
Displays the month as a three-letter abbreviation (except for May) without a period. |
|
Displays the full name of the month. |
|
Displays the full localized name of the month. |
|
Displays a number from 1 to 4 giving the quarter of the year. |
|
Displays an integer from 1 to 366 giving the day of the year. |
|
Displays a number from 00 to 99 giving the two-digit year. |
|
Displays a number from 0100 to 9999 giving the four-digit year. |
|
Displays a number from 0 to 23 giving the hour. |
|
Displays a number from 00 to 23 giving the two-digit hour. |
|
Displays a number from 0 to 60 giving the minute. |
|
Displays a number from 00 to 60 giving the two-digit minute. |
|
Displays a number from 0 to 60 giving the second. |
|
Displays a number from 00 to 60 giving the two-digit second. |
|
Displays the full time (hour, minute, and second) in the system's default time format. |
|
Uses the 12-hour clock and displays AM or PM as appropriate. |
|
Uses the 12-hour clock and displays am or pm as appropriate. |
|
Uses the 12-hour clock and displays A or P as appropriate. |
|
Uses the 12-hour clock and displays a or p as appropriate. |
|
Uses the 12-hour clock and displays the AM or PM string literal defined for the system. |
For example, the following statement returns
:Saturday, April 01, 2019
Format(#4/1/2019#, "dddddd")
The
function also lets you create custom string formats using the options shown in Table 9.7.Format
TABLE 9.7: Characters for creating your own string formats
CHARACTER | EXPLANATION |
|
Placeholder for a character. Displays a character if there is one, and a space if there is none. |
|
Placeholder for a character. Displays a character if there is one, and nothing if there is none. |
|
Displays the string in lowercase. |
|
Displays the string in uppercase. |
|
Causes VBA to fill placeholders from left to right instead of from right to left (the default direction). |
For example, the following statement assigns to
a string consisting of four spaces if there is no input in the input box:strUser
strUser = Format(InputBox("Enter your name:"), "@@@@")
To insert special characters (such as a carriage return or a tab) into a string, specify a built-in constant (for those special characters that have built-in constants defined). Or enter the appropriate character code using the
function. The syntax for the Chr
function is straightforward:Chr
Chr(charactercode)
Here,
is a number that identifies the special character you want to add.charactercode
Table 9.8 lists the most useful character codes and character constants.
TABLE 9.8: VBA character codes and character constants
CODE | BUILT-IN CHARACTER CONSTANT | CHARACTER |
|
|
Tab |
|
|
Line feed |
|
|
Soft return (Shift+Enter) |
|
|
Page break |
|
|
Carriage return |
|
|
Carriage return/line feed combination |
|
N/A | Column break |
|
N/A | Double straight quotation marks (") |
|
N/A | Single straight quotation mark/apostrophe (') |
|
N/A | Opening single smart quotation mark (‘) |
|
N/A | Closing single smart quotation mark/ apostrophe (') |
|
N/A | Opening double smart quotation mark (“) |
|
N/A | Closing double smart quotation mark (”) |
|
N/A | Bullet |
|
N/A | En dash |
|
N/A | Em dash |
Here's a practical example exploiting the
function. Say you want to build a string containing a person's name and address from individual strings containing items of that information. You also want the individual items separated by tabs in the resulting string so that you could insert the string into a document and then easily convert it into a table.Chr
To do this, you could use the following code:
Sub FormatTabular()
Dim i As Integer
Dim strFirstName As String
Dim strLastName As String
Dim strAddress As String
Dim strCity As String
Dim strState As String
Dim strAllInfo As String
strFirstName = "Phil"
strLastName = "Mortuqye"
strAddress = "12 Batwing Dr."
strCity = "Tulsa"
strState = "OK"
strAllInfo = strFirstName & vbTab & strLastName _
& vbTab & strAddress & vbTab & strCity _
& vbTab & strState & vbCr
Selection.TypeText strAllInfo
End Sub
String variables are assigned to the string
by concatenating the strings strAllInfo
, strFirstName
, and so on with tabs—strLastName
characters—between them. The final character added to the built string is vbTab
(a carriage-return character), which creates a new paragraph.vbCr
The final line enters the
string into the current document, thereby building a tab-delimited list containing the names and addresses. This list can then be easily converted into a table with columns that each contain one item of information: The first column contains the strAllInfo
string, the second column the strFirstName
string, and so on.strLastName
String variables are often useful for holding text. You can use them to store any quantity of text, from a character or two up to a large number of pages from a Word document or other text document. You can also use strings to store specialized information, such as filenames and folder names. Once you've stored text in a string, you can manipulate it according to your needs.
Table 9.9 lists VBA's built-in functions for manipulating strings. Because many of these functions are useful and some are complex, you'll find detailed examples after the table.
TABLE 9.9: VBA's string-manipulation functions
FUNCTION (ARGUMENTS) | RETURNS |
, , , |
A Variant/Long giving the position of the first instance of the search string ( ) inside the target string ( ), starting from the beginning of the target string. |
, , ,
|
A Variant/Long giving the position of the first instance of the search string ( ) inside the target string ( ), starting from the end of the target string. |
|
A String containing the lowercased . |
,
|
A Variant/String containing the specified number of characters from the left end of . |
|
A Long containing the number of characters in . |
|
A Variant/String containing with any leading spaces trimmed off it. |
, ,
|
A Variant/String containing the specified number of characters from the specified starting point within . |
,
|
A Variant/String containing the specified number of characters from the right end of . |
|
A Variant/String containing with any trailing spaces trimmed off it. |
|
A Variant/String containing of spaces. |
, ,
|
A Variant/Integer containing the result of comparing and . |
, ,
|
A Variant/String containing converted as specified by conversion for the (optional) specified Locale ID . |
,
|
A Variant/String containing of instances of . |
|
A String containing the characters of in reverse order. |
|
A Variant/String containing with any leading spaces or trailing spaces trimmed off it. |
|
A String containing the uppercased . |
Sometimes you'll need to use only part of a string in your macros. How would you extract only the first three characters of the names of a list of cities to create a location code for each?
VBA provides several functions for returning from strings the characters you need:
Left
function returns a specified number of characters from the left end of the string.Right
function returns a specified number of characters from the right end of the string.Mid
function returns a specified number of characters starting from a specified location inside a string.The
function returns the specified number of characters from the left end of a string. The syntax for the Left
function is as follows:Left
Left(string, length)
Here, the
argument is any string expression—that is, any expression that returns a sequence of contiguous characters. string
returns Left
if Null
contains no data. The string
argument is a numeric expression specifying the number of characters to return. length
can be a straightforward number (such as 4, or 7, or 11) or it can be an expression that results in a number. For example, if the length of a word were stored in the variable named length
and you wanted to return two characters fewer than LenWord
, you could specify the expression LenWord
LenWord
-
as the 2
argument; to return three characters more than length
, you could specify LenWord
LenWord
+
as the 3
argument.length
One way to use the
function would be to separate the area code from a telephone number that was provided as an unseparated 10-digit number from a database. In the following statements, the telephone number is stored in the String variable Left
, which the code assumes was created earlier:strPhone
Dim strArea As String
strArea = Left(strPhone, 3)
These statements create the variable
and fill it with the leftmost three characters of the variable Area
.strPhone
The
function is the mirror image of the Right
function. Left
returns a specified number of characters from the right end of a string. The syntax for the Right
function is as follows:Right
Right(string, length)
Again, the
argument is any string expression, and string
is a numeric expression specifying the number of characters to return. And, again, length
returns Right
if Null
contains no data, and string
can be a number or an expression that results in a number.length
To continue the previous example, you could use the
function to separate the last seven digits of the phone number stored in the string Right
from the area code:strPhone
Dim strLocalNumber As String
strLocalNumber = Right(strPhone, 7)
These statements create the variable
and fill it with the rightmost seven characters from the variable strLocalNumber
.strPhone
The
and Left
functions extract a substring from the left or right side of a string. The Right
function fetches a substring out of the middle of a string. It is necessarily a bit more complicated; but it is quite flexible.Mid
The
function returns a specified number of characters from inside a given string. You specify a starting position in the string and the number of characters (to the right of the starting position) that you want extracted.Mid
The syntax for the
function is as follows:Mid
Mid(string, start[, length])
Here are the elements of the syntax:
Left
and Right
, the string
argument is any string expression. Mid
returns Null
if string
contains no data.start
is a numeric value specifying the character position in string
at which to start the length
selection. If start
is larger than the number of characters in string
, VBA returns a zero-length string. In code, an empty string is typed as two quotation marks with nothing inside: strState = ""
.length
is an optional numeric expression specifying the number of characters to return. If you omit length
or use a length
argument greater than the number of characters in string
, VBA returns all the characters from the start
position to the end of string
. length
can be an ordinary literal number or an expression that results in a number.Using the phone-number example, you could employ
to pluck the local exchange code out from within a 10-digit phone number (for instance, extract the 555 from 5105551212), like this:Mid
Dim strPhone As String
strPhone = "5105551212"
MsgBox Mid(strPhone, 4, 3)
This statement displays three characters in the variable
, starting at the fourth character.strPhone
You've seen how to extract a substring using
, but this function has another use as well. You can also use Mid
to find the location of a character within a string. In the following snippet, the Mid
loop walks backward through the string Do Until…
(which contains the strFilename
property of the template attached to the active document in Word) until it reaches the first backslash (FullName
), storing the resulting character position in the Integer variable
. The message box then displays that part of intLen
to the right of the backslash (determined by subtracting strFilename
from the length of intLen
)—the name of the attached template without its path:strFilename
Dim strFilename As String, intLen As Integer
strFilename = ActiveDocument.AttachedTemplate.FullName
MsgBox strFilename
intLen = Len(strFilename)
Do Until Mid(strFilename, intLen, 1) = ""
intLen = intLen - 1
Loop
MsgBox Right(strFilename, Len(strFilename) - intLen)
This example is more illustrative than realistic for two reasons: First, you can get the name of the template more easily by just using the
property rather than the Name
property. Second, there's a function called FullName
(discussed next) that returns the position of one string within another by walking backward through it.InStrRev
You can use the
function to find an individual character within a string, but what if you need to find a set of characters within a string? The Mid
function is designed to find one string within another string. For example, you could check, say, the current paragraph to see if it contained a particular word. If it did, you could take action accordingly—for instance, replacing that word with another word or selecting the paragraph for inclusion in another document. Maybe your company has changed its name and you need to do a search and replace in a large number of document templates.InStr
The
function is the counterpart of the InStrRev
function, working in a similar way but in the reverse direction.InStr
The syntax for
is as follows:InStr
InStr([start, ]string1, string2[, compare])
Here are the arguments:
start
is an optional argument specifying the starting position in the first string, string1
. If you omit start
, VBA starts the search at the first character in string1
(which is usually where you want to start). However, you do need to use start
when you use the compare
argument to specify the type of string comparison to perform.string1
is a required argument specifying the string expression in which to search for string2
.string2
is a required argument specifying the string expression for which to search in string1
.compare
is an optional argument specifying the type of string comparison you want to perform. Text can be compared two ways: a binary comparison, which is case sensitive, or a textual comparison, which is not case sensitive. The default is a binary comparison, which you can specify by using the constant vbBinaryCompare
or the value 0
for compare
. Although specifying this value isn't necessary (because it's the default), you might want to include it to make your code ultra-clear. To specify a textual, case-insensitive comparison, use the constant vbTextCompare
or the value 1
for compare
.Another way to use
is to find the location of a certain string within another string so that you can then change that substring. You might want to do this if you needed to move a file from its current position in a particular folder or subfolder to another folder that had a similar subfolder structure. For instance, suppose you work with documents stored in a variety of subfolders beneath a folder named In (such as InStr
), and after you're finished with them, you save them in corresponding subfolders beneath a folder named Out (z:DocumentsIn
). The short procedure shown in Listing 9.1 automatically saves the documents in the subfolder Out.z:DocumentsOut
The code in Listing 9.1 works as follows:
strOName
(as in original name), the String variable strNName
(as in new name), and the Integer variable intToChange
. Line 3 then assigns strOName
the FullName
property of the ActiveDocument
object: the full name of the active document, including the path to the document (for example, z:DocumentsInLettersMy
Letter.docm
).intToChange
the value of the InStr
function that finds the string In
in the variable strOName
. Using the example path from the previous paragraph, intToChange
will be assigned the value 13 because the first character of the In
string is the thirteenth character in the strOName
string.strNName
the new filename created in the main part of the statement. This breaks down as follows:
Left(strOName,
intToChange
-
1)
takes the left section of the strOName
string, returning the number of characters specified by intToChange
-
1
—the number stored in intToChange
minus one.&
"Out"
adds to the partial string specified in the previous bullet item (to continue the previous example, z:Documents
) the characters Out
, which effectively replace the In
characters, thereby changing the directory name (z:DocumentsOut
).&
Right(strOName,
Len(strOName)
-
intToChange
-
3)
completes the partial string by adding the right section of the strOName
string, starting from after the In
string (LettersMy
Letter.docm)
, giving z:DocumentsOutLettersMy
Letter.docm
. The number of characters to take from the right section is determined by subtracting the value stored in intToChange
from the length of strOName
and then subtracting 3 from the result. Here, the value 3 comes from the length of the string In
; because the intToChange
value stores the character number of the first backslash, you need count only the I, the n, and the second backslash to reach its end.strNName
variable.The syntax for
is similar to that of InStrRev
:InStr
InStrRev(stringcheck, stringmatch[, start[, compare]])
These are the arguments:
stringcheck
is a required String argument specifying the string in which to search for stringmatch
.stringmatch
is a required String argument specifying the string for which to search.start
is an optional numeric argument specifying the starting position for the search. If you omit start
, VBA starts at the last character of stringcheck
.compare
(as for InStr
) is an optional argument specifying how to search: vbTextCompare
for text, vbBinaryCompare
for a binary comparison.Often you'll need to trim strings before concatenating them to avoid ending up with extra spaces in inappropriate places, such as in the middle of eight-character filenames. Recall the telephone-number example where your program wanted no spaces, but you permitted the user to input spaces in them without penalty.
Data can contain appended or prepended spaces. What's more, users might randomly type spaces in various ways when entering data. You never know. Your programming (and databases), however, need data in a predictable format (so the data can easily be searched, sorted, and otherwise manipulated).
For example, if 500 users entered their zip codes, one or two of them might type a space before entering the digits. Any such entries would be placed at the start of a list after the list was alphabetically sorted (the space character is seen as “lower” than ordinary characters by a sorting function). So, the sort would produce an inaccurate result. It's easy, though, to use the
functions to get rid of unwanted spaces.Trim
As you saw in Table 9.9, VBA provides three functions specifically for trimming leading spaces and trailing spaces from strings:
LTrim
removes leading spaces from the specified string.RTrim
removes trailing spaces from the specified string.Trim
removes both leading and trailing spaces from the specified string.The syntax for the
, LTrim
, and RTrim
functions is straightforward:Trim
LTrim(string)
RTrim(string)
Trim(string)
In each case,
is any string expression.string
You could use the
function to remove both leading and trailing spaces from a string derived from the current selection in the active document in Word. The first line in this next code example declares Trim
and strUntrimmed
as String variables. The second line assigns the data in the current selection to the strTrimmed
string. The third line assigns the trimmed version of the strUntrimmed
string to the strUntrimmed
string:strTrimmed
Dim strUntrimmed As String, strTrimmed As String
strUntrimmed = Selection.Text
strTrimmed = Trim(strUntrimmed)
To find out how long a string is, use the
function. The syntax for the Len
function is straightforward:Len
Len(string)
Here,
is any valid string expression. (If string
is string
, Null
also returns Len
.)Null
One use for
is to make sure a user's entry in an input box or in a text box on a form is of a suitable length. A United States phone number must be 10 digits, for instance.Len
The
procedure shown in Listing 9.2 uses CheckPassword
to make sure a password the user enters is long enough to be difficult to guess, but not too long.Len
Listing 9.2 ensures that a password contains between 6 and 15 characters (inclusive). Here's how the code works:
strPassword
.BadPassword
, to which the GoTo
statements in line 9 and line 12 redirect execution if the password fails either of the checks.
Labels are locations within code that you might need to jump to during execution. A VBA label is a word on its own line in the code that ends with a colon, as you can see. Labels are discussed in Chapter 11, “Making Decisions in Your Code.”
strPassword
the result of an input box that invites the user to enter the password for the item.If
statement to check that the password is an appropriate length.
strPassword
for zero length, which would mean that the user clicked either the Cancel button or the Close button on the input box or clicked the OK button with no text entered in the input box.strPassword
is zero, the End
statement in line 6 terminates the procedure.BadPassword
label.BadPassword
label.If you need to change the case of a string, use the
(short for string conversion), StrConv
, and LCase
functions. Of these, the easiest to use is UCase
, which can convert a string to a variety of different formats varying from straightforward uppercase, lowercase, or propercase (as VBA refers to initial capitals, also known as title case) to the Japanese hiragana and katakana phonetic characters.StrConv
The
function has the following syntax:StrConv
StrConv(string, conversion)
Here, the
argument is any string expression, and the string
argument is a constant or value specifying the type of conversion required. The most useful conversion constants and values are shown in Table 9.10.conversion
TABLE 9.10: The most common conversion constants
CONSTANT | VALUE | EFFECT |
|
|
Converts the given string to uppercase characters. |
|
|
Converts the given string to lowercase characters. |
|
|
Converts the given string to propercase (aka title case—the first letter of every word is capitalized). |
|
|
Converts the given string to Unicode using the system's default code page. |
|
|
Converts the given string from Unicode to the system's default code page. |
For example, suppose you received from a database program a string called
containing a person's name. You could use strCustomerName
to make sure that it was in title case by using a statement such as this:StrConv
strProperCustomerName = StrConv(strCustomerName, vbProperCase)
If you don't feel like using
, you can alternatively use the StrConv
and LCase
functions, which convert a string to lowercase and uppercase, respectively. UCase
is frequently used to avoid case-sensitivity in languages like XML that make a distinction (in their variable names) between upper- and lowercase letters. In other words, LCase
and ThisVariableName
are considered entirely different variables. If you try to use two variable names with different capitalization, the VBA Code Editor will automatically force them to be identically capitalized.ThisVariablename
VBA, however, is case-sensitive when comparing string data.
and LCase
have the following syntax:UCase
LCase(string)
UCase(string)
Here,
is any string expression.string
For example, the following statement lowercases the string
and assigns it to MyString
:MyLowerString
MyLowerString = LCase(MyString)
As you've seen already, you can compare one item to another item by simply using the
operator:=
If 1 = 1 Then MsgBox "One is one."
This straightforward comparison with the
operator also works with two strings, as shown in the second line here:=
strPet = InputBox("Is your pet a dog or a cat?", "Pet")
If strPet = "Dog" Then MsgBox "We do not accept dogs."
The problem with this code as written is that the strings need to match exactly in capitalization for VBA to consider them equal. If the user enters
or dog
(not to mention DOG
, dOG
, doG
, or dOg
) rather than DoG
, the condition isn't met. Again, permit your users a variety of correct responses—don't enforce pointless capitalization and punctuation rules.Dog
Too many programmers would respond to a user input of dog with an error message like this: “Please ensure that only the first letter is capitalized. Let's try this again, you poor sod.”
To accept variations of capitalization, you could use the
operator to hedge your bets:Or
If Pet = "Dog" Or Pet = "dog" Or Pet = "DOG" Or Pet = "dogs" _
Or Pet = "Dogs" or Pet = "DOGS" Then MsgBox _
"We do not accept dogs."
As you can see, such code rapidly becomes clumsy, even omitting some variations such as
. Or you could change the case of one or both strings involved to make sure their case matched, but it's simpler to just use the dOG
function, which is designed to permit you to ignore case. The syntax for StrComp
is as follows:StrComp
StrComp(string1, string2 [, compare])
Here,
and string1
are required String arguments specifying the strings to compare, and string2
is an optional argument specifying textual comparison (compare
) or binary comparison (vbTextCompare
).vbBinaryCompare
The following statement uses
to settle the pet question once and for all:StrComp
If StrComp(strPet, "dog", vbTextCompare) = 0 Then _
MsgBox "We do not accept dogs."
Another approach would be to just
the input and compare it to a lowercase test string:LCase
If LCase(strPet)= "dog" Then _
MsgBox "We do not accept dogs."
VBA provides a solid suite of functions for standard mathematical operations. Table 9.11 lists these functions with examples.
TABLE 9.11: VBA's mathematical functions
FUNCTION(ARGUMENT) | RETURNS | EXAMPLE |
|
The absolute value of —the unsigned magnitude of the number. |
returns . |
|
The arctangent of in radians. |
|
|
The cosine of angle . |
|
|
e, the base of natural logarithms, raised to the power of . |
returns . |
|
The integer portion of (without rounding). If is negative, returns the negative number greater than or equal to . |
returns . returns . |
|
The integer portion of (again, without rounding). If is negative, returns the negative number less than or equal to . |
returns . returns . |
|
The natural logarithm of . |
|
|
A random number (with no argument) or a number based on the given initial seed. | returns a random number. |
|
if is negative, if is , if is positive. |
returns . returns . returns . |
|
The sine of the angle specified by (measured in radians). |
|
|
The square root of . If is negative, VBA gives a runtime error. |
returns . |
|
The tangent of the angle specified by (measured in radians). |
|
VBA provides a full complement of date and time functions, as listed in Table 9.12. The table provides brief examples of working with the functions. The sections after the table provide longer examples showing how to use some of the more complex functions.
TABLE 9.12: VBA's date and time functions
FUNCTION (ARGUMENTS) | RETURNS | EXAMPLE |
|
A Variant/Date containing the current date according to your computer | might display . (The format depends on your Windows date settings.) |
, ,
|
A Variant/Date containing the date of the specified interval after the specified date | returns . |
,
|
The part (specified by ) of the specified date |
See the example in the next section. |
, ,
|
A Variant/Date containing the date for the specified year, month, and day | . |
|
A Variant/Date containing the specified date | |
|
A Variant/Integer between 1 and 31, inclusive, representing the day of the month for
|
|
|
A Variant/Integer between 0 and 23, inclusive, representing the hour for
|
|
|
A Variant/Integer between 0 and 59, inclusive, representing the minute for
|
|
|
A Variant/Integer between 1 and 12, inclusive, representing the month for
|
|
|
A String containing the name of the month represented by
|
displays a message box containing the current month. |
|
A Variant/Date containing the current date and time according to your computer | might display . (The format of date and time will depend on your Windows date settings.) |
|
A Variant/Integer between 0 and 59, inclusive, representing the second for
|
|
|
A Variant/Date containing the current time according to your computer | might display . (The time format and time will depend on your Windows date settings.) |
|
A Single giving the number of seconds that have elapsed since midnight | |
, ,
|
A Variant/Date containing the time for the specified hour, minute, and second | returns . (The format will depend on your Windows date settings.) |
|
A Variant/Date containing the time for
|
|
|
A Variant/Integer containing the day of the week represented by
|
See the next entry. |
|
A String containing the weekday denoted by
|
returns , the day of the week for April Fool's Day 2019. |
The
function lets you take a date and separate it into its components. You can often achieve the same results by using other date functions, but DatePart
is a good tool to have in your VBA toolbox.DatePart
The syntax for
is as follows:DatePart
DatePart(Interval, Date[,FirstDayOfWeek[, FirstWeekOfYear]])
The components of the syntax are as follows:
Interval
is a required String expression giving the unit in which you want to measure the interval: yyyy
for year, q
for quarter, m
for month, y
for the day of the year, d
for day, w
for weekday, ww
for week, h
for hour, n
for minute (because m
is for month), and s
for second.Date
is a required Variant/Date giving the date you want to examine.FirstDayOfWeek
is an optional constant specifying the day that starts the week (for date information). The default setting is vbSunday
(1
), but you can also set vbMonday
(2
), vbTuesday
(3
), vbWednesday
(4
), vbThursday
(5
), vbFriday
(6
), vbSaturday
(7
), or vb UseSystem
(0
; this uses the system setting).FirstWeekOfYear
is an optional constant specifying the week considered first in the year. Table 9.13 shows the options for this constant.TABLE 9.13: The options for the FirstWeekOfYear constant
CONSTANT | VALUE | YEAR STARTS WITH WEEK |
|
|
Use the system setting. |
|
|
The week in which January 1 falls (the default setting). |
|
|
The first week with a minimum of four days in the year. |
|
|
The first full week (7 days) of the year. |
For example, the following statement assigns the current year to the variable
:dteThisYear
dteThisYear = DatePart("yyyy", Date)
The
function returns the interval (the number of days, weeks, hours, and so on) between two specified dates. The syntax for DateDiff
is as follows:DateDiff
DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]])
Here are the components of the syntax:
interval
is a required String expression giving the unit in which you want to measure the interval: yyyy
for year, q
for quarter, m
for month, y
for the day of the year, d
for day, w
for weekday, ww
for week, h
for hour, n
for minute (because m
is for month), and s
for second.date1
and date2
are the dates between which you're calculating the interval.firstdayofweek
is an optional constant specifying the day that starts the week (for date information). The default setting is vbSunday
(1
), but you can also set vbMonday
(2
), vbTuesday
(3
), vbWednesday
(4
), vbThursday
(5
), vbFriday
(6
), vbSaturday
(7
), or vb UseSystem
(0
; this uses the system setting).firstweekofyear
is an optional constant specifying the week considered first in the year. Table 9.13 shows the options for this constant.For example, the following statement returns the number of weeks between June 3, 2009, and September 30, 2009:
MsgBox DateDiff("ww", "6/3/2009", "9/30/2009")
The
function lets you easily add an interval of time to, or subtract an interval of time from, a specified date, returning the resulting date. The syntax for DateAdd
is as follows:DateAdd
DateAdd(interval, number, date)
Here are the components of the syntax:
interval
is a required String expression giving the unit of measurement for the interval: yyyy
for year, q
for quarter, m
for month, y
for the day of the year, d
for day, w
for weekday, ww
for week, h
for hour, n
for minute, and s
for second.number
is a required numeric expression giving the number of intervals to add (a positive number) or to subtract (a negative number). If number
isn't already of the data type Long, VBA rounds it to the nearest whole number before evaluating the function.date
is a required Variant/Date or literal date giving the starting date.For example, the following statement returns the date 10 weeks from May 27, 2019:
DateAdd("ww", 10, #5/27/2019#)
The following sections demonstrate how to use a couple of key VBA file-management functions: the
function, which you use to find out whether a file exists, and the Dir
function, which returns the current path.CurDir
Often when managing files, you'll need to first check whether a particular file already exists on the hard drive. For instance, if you're about to save a file, you may want to make sure the save operation won't overwrite an existing file—a file with the same name in the same location on the hard drive.
If you're about to open a file, you might want to see if that file exists before you use the
method; otherwise, VBA will give an error.Open
To test whether a file exists, you can use a straightforward procedure such as the one shown in Listing 9.3.
This procedure in Listing 9.3 uses the
function to check whether a file exists and displays a message box indicating whether it does or doesn't. Figure 9.3 shows examples of the message box. This message box is for demonstration purposes only. In a real-world macro you'd likely use the result of the test to branch (execute different code blocks) based on whether the file exists. Branching is covered in Chapter 11.Dir
Here's how the code works:
strTestFile
, strNameToTest
, and strMsg
.strNameToTest
.strNameToTest
to a blank string (which means the user clicked the Cancel button in the input box or clicked the OK button without entering any text in the text box) and uses an End
statement to end the procedure if it gets a match.strTestFile
the result of running the Dir
function on the strNameToTest
string. If Dir
finds a match for strNameToTest
, strTestFile
will contain the name of the matching file; otherwise, it will contain an empty string.If…Then
statement by testing the length of the strTestFile
string. If the length is 0, the statement in line 7 assigns to strMsg
text saying that the file doesn't exist; otherwise, VBA branches to the Else
statement in line 8 and runs the statement in line 9, assigning text to strMsg
saying that the file does exist. Line 10 ends the If
statement.strMsg
. Line 12 ends the procedure.You can find out the current path (the location on the hard drive to which the host application is currently pointed) on either the current drive or a specified drive by using the
function. Often, you'll need to change the current path (using the CurDir
function) to make sure the user is saving files in, or opening files from, a suitable location.ChDir
To return the current path, use
without an argument:CurDir
CurDir
To return the current path for a specified drive, enter the drive letter as an argument. For example, to return the current path on drive D, use this statement:
CurDir("D")
You can write your own functions by writing code between
and Function
in the VBA Editor. Chapter 10, “Creating Your Own Functions,” explores how to write such custom functions. In addition to functions you might write, there are many functions already prewritten in VBA—ready for you to call them from your macros to perform various tasks.End Function
MsgBox
function displays a message box containing whatever data you request. The only required argument for this function is the prompt
. The Now
function returns the current date and time. Write a line of code that calls the MsgBox
function and uses the Now
function as its argument."12"
(which, in reality, is two text characters, the digits 1 and 2) into an Integer data type, the actual number 12, that you can manipulate mathematically? " this "
into
"this"