Last week I wrote about a string manipulation issue that a reader was having. This was a great way to illustrate some of the string manipulation techniques that I covered in previous columns. As I noted then, the string manipulation is only one part of the problem. Providing a way to search for all cells that need to be fixed is the second part of the issue.
While Excel provides Find and FindNext methods to search cells, using them correctly isn’t as easy as one might think. The reason that using Find is more difficult than it should be is that as long as it finds at least one match, calls to FindNext will never terminate because it will repeatedly find the same item. This happens because once Excel gets to the last cell in the range it wraps around and resumes searching with the first cell in the range.
The key to using Find and FindNext is saving the address of the first cell that is found and then comparing the address of subsequent finds with the saved address. When a subsequent address equals the saved address, the entire range has been searched.
Listing 1 provides and example illustrating this method. It looks a lot longer than it really is because of all the comments I’ve added.
Listing 1: Using Find and FindNext to search cells on a worksheet
Sub FindExample()
Dim rgFound As Range
Dim sFirstFoundAddress As String
' Be careful using ActiveSheet - you have to make sure
' it is a worksheet if you'll be doing worksheet-specific
' things to it.
If ActiveSheet.Type <> XlSheetType.xlWorksheet Then
MsgBox “The active sheet is not a worksheet.”, vbOKOnly
Exit Sub
End If
‘ In the initial call to Find, it is a good idea to specify
‘ all the values. The values are “sticky” - they’ll last in
‘ between calls or uses from the user interface which is why
‘ you should explicitly specify the values you want rather
‘ then relying on “default” values.
Set rgFound = ActiveSheet.Cells.Find(What:=”NAR”, _
After:=ActiveCell, LookIn:=xlValues, _
LookAt:=xlPart, SearchDirection:=xlNext, _
MatchCase:=False)
‘ If nothing is found, Find sets the range (rgFound in this
‘ case) to Nothing.
If Not rgFound Is Nothing Then
‘ To prevent an endless loop, save the address of the
‘ first found item.
sFirstFoundAddress = rgFound.Address
MsgBox “Found match as cell ” & rgFound.Address
‘ Continue finding subsequent items by calling out
‘ to FindNext.
Set rgFound = ActiveSheet.Cells.FindNext(rgFound)
‘ Start a loop for finding all remaining items.
Do Until rgFound Is Nothing
‘ Once find gets to the end of a worksheet, it
‘ loops back to the first cell. To prevent endless
‘ loops, compare any found cells to the first found
‘ cell to see if you’ve already found it.
If rgFound.Address = sFirstFoundAddress Then
Exit Do
Else
MsgBox “Found match as cell ” & rgFound.Address
End If
Set rgFound = ActiveSheet.Cells.FindNext(rgFound)
Loop
End If
MsgBox “The active sheet has been searched.”, _
vbOKOnly, “Search Complete”
End Sub
One thought that I’d like to share relates to the use of ActiveSheet. Generally, ActiveSheet will resolve to a worksheet object. However, when using ActiveSheet, be sure to make sure that the active sheet is actually a worksheet. It could be a chart sheet for example which may result in runtime errors if you have assumed that ActiveSheet is a worksheet. It is easy to validate that ActiveSheet is a worksheet by examining the Type property as I’ve done near the beginning of Listing 1.
To test this procedure, simply populate several cells in a worksheet with the value “NAR”. With the worksheet active, run the FindExample macro.