"Search and Replace" in Visual Basic Applications

Foreword

Although Visual Basic is not one of my favorite languages, I like its simplicity and rich set of libraries. Many times when developing an application that deals with an enormous amount of textual data, you need a functionality that makes the job of correcting misspelt words easier. Microsoft Word, for example, when running a "Spell Check" gives you an opportunity to correct a wrongly typed word (through suggestions). It also facilitates a "Search and Replace" tool that can be used for user-defined word replacments. Here in this article, I am not going to give you details about implementing a dictionary; rather, I focus on how this feature (find and replace) can be implemented in a VB application.

Prerequisites

While I explain the code, I assume that you have worked in Visual Basic and are familiar with various in-built controls and library functions (I have used a few of them) that are available from within the Visual Studio IDE. I have tried to keep the code as simple as possible, and you will be able to understand the logic in a while. If you want to know more about some library functions (such as its syntax, params, and so forth) visit MSDN online.

Groundwork

Create a Standard EXE VB project. Rename the default form as frmMainForm. Add a menu to the default form with the following details (the & sign is used for accelerator key and the name preceded with word mnu depicts menu-item's internal name (used in code)),

&Edit
...&Find and Replace   mnuFindandreplace
E&xit                  mnuExit

Add a TextBox control to this form and rename it as txtClientArea. Stretch and adjust it with mouse so that it covers entire client-area of the form. Set this TextBox's MultiLine property to True from the Properties window.

Add another form to this project (from Project > Add Form). Rename this form as frmFindReplace and set its BorderStyle property to 4 - FixedToolWindow from the Properties window. Now, add two TextBox controls and rename them as txtSearchTerm and txtReplaceWithString respectively. Add a checkbox control and rename it as chkCaseSense. Finally, add a CommandButton to the form and rename it as cmdReplace.

In the frmMainForm, you will write the following code:

Private Sub mnuExit_Click()
   End
End Sub

Private Sub mnuFindandreplace_Click()
   frmFindReplace.FindnReplace txtClientArea
End Sub

It is apparent from the above code that when the user clicks on the "Exit" menu item we want to terminate the application and when he selects the "Find and Replace" submenu item from the "Edit" menu, you want to activate the frmFindReplace form by the means of calling public interface of frmFindReplace; in other words, FindnReplace(). This public interface allows the search algorithm to be generic. With this interface, you provide your TextBox as an argument (in which the search is to be performed). By replacing the name txtClientArea with your own TextBox's name, you can invoke the same search-replace functionality for as many TextBoxes (as well as many times) as desired, without repeating the search code. The main code of "Search and Replace" is, however, placed under the frmFindReplace form only. The code for this module follows.

Source Code

' This variable is used for making the algorithm generic.
Dim txtClient As TextBox

' This method is the public interface to SnR functionality.
Public Sub FindnReplace(ByRef Tb As TextBox)
   Set txtClient = Tb
   Me.Show , txtClient.Parent
End Sub

Private Sub cmdReplace_Click()
   Dim CaseSense      As Integer
   Dim SourceText     As String
   Dim SourceTextCopy As String
   Dim Cnt            As Integer

   ' Check for the case sensitivity options
   If (chkCaseSense.Value = vbChecked) Then
      CaseSense = 0
   Else
      CaseSense = 1
   End If

   ' One contains the original text and another contains replaced
   ' (updated) one.
   ' Used to check whether a replacement was done or not.
   SourceText = txtClient.Text
   SourceTextCopy = SourceText

   If Len(SourceText) = 0 Then
      Exit Sub
    End If

On Error GoTo ErrHandler
   Dim SearchTermLen As Integer
   Dim FndPos As Integer

   SearchTermLen = Len(txtSearchTerm.Text)
   ' Search from the begining of the document.
   Cnt = 1

' This is endless loop (terminated on a condition checked inside
' the loop body).
While (1)

   FndPos = InStr(Cnt, SourceText, txtSearchTerm.Text, CaseSense)

   ' When a match is found, replace it appropriately.
   If (FndPos > 0) Then
      SourceText = ReplaceFun(SourceText, FndPos, _
                   Len(txtSearchTerm.Text), _ 
                   txtReplaceWithString.Text)
      Cnt = FndPos + SearchTermLen
   Else
      Cnt = Cnt + 1
   End If

   ' Whether a replacement was done at all or not
   If (Cnt >= Len(SourceText)) Then
      txtClient.Text = SourceText
      If (SourceTextCopy <> SourceText) Then
         MsgBox "Finished replacing all occurrences.", _
                vbInformation + vbOKOnly, _
                "Replaced All"
      Else
         MsgBox "No matching strings found. No text replaced.", _
                vbInformation + vbOKOnly, _
                "No Replacement"
      End If
      Unload Me
      Exit Sub
   End If
      ' Else Restart from henceforth
Wend
Exit Sub

ErrHandler:
    Response = MsgBox("An error ocurred while searching. Inform _
               the developer with details.", _
               vbExclamation + vbOKOnly, "Error Searching")
End Sub

Private Sub Form_Load()
   ' Default SearchTerm must be the one selected by the user in
   ' MainForm
   If Len(txtClient.SelText) <> 0 Then
      txtSearchTerm.Text = txtClient.SelText
   End If
End Sub

Function ReplaceFun(Source As String, FromPos As Integer, _
                    Length As Integer, StringTBReplaced _
                    As String) As String
   ' Replaces a source string with new one appropriately
   Dim ResultStr As String

   ResultStr = Left(Source, FromPos - 1)
   ResultStr = ResultStr & StringTBReplaced
   ResultStr = ResultStr & Right(Source, Len(Source) - FromPos - _
                                 Length + 1)

   ReplaceFun = ResultStr
End Function

Private Sub txtReplaceWithString_Change()
   Call EnableDisableReplaceButton
End Sub

Private Sub txtReplaceWithString_GotFocus()
   ' Select the contents of the textbox
   If Len(txtReplaceWithString.Text) <> 0 Then
      txtReplaceWithString.SelStart = 0
      txtReplaceWithString.SelLength = Len(txtReplaceWithString.Text)
   End If
End Sub

Private Sub txtSearchTerm_Change()
   Call EnableDisableReplaceButton
End Sub

Private Sub EnableDisableReplaceButton()
   If Len(txtSearchTerm.Text) <> 0 _
      And Len(txtReplaceWithString.Text) <> 0 Then
      cmdReplace.Enabled = True
   Else
      cmdReplace.Enabled = False
    End If
End Sub

Private Sub txtSearchTerm_GotFocus()
   ' Select the contents of textbox
   If Len(txtSearchTerm.Text) <> 0 Then
      txtSearchTerm.SelStart = 0
      txtSearchTerm.SelLength = Len(txtSearchTerm.Text)
   End If
End Sub

"Search and Replace" in Visual Basic Applications

Modus Operandi

The public interface SearchnReplace is used to make the algorithm generic. With this approach, the search and replace functionality can now be implemented in any application without disturbing the code of frmFindReplace. The only place from where the public interface is called; it needs to be changed.

The primary code of "Search and Replace" (SnR) is under cmdReplace_Click() procedure and ReplaceFun() function. Begin with the former.

First, the CaseSense variable is used for keeping track of the user's selection of case sensitivity. It is set to 0 if the user wants a case-sensitive SnR; 1 otherwise. The SourceText and SourceTextCopy variables are used to hold frmMainForm's txtClientArea's contents (or that TextBox's contents that the user supplies from the main form. In your case, it is txtClientArea). Two variables' usage for the same content will be apparent in the following description (one being a temporary storage). The Cnt variable is used to keep track of the end-of-document and is useful when re-iterating the SnR from the beginning of the document. This variable internally depicts the current cursor position, from which the next SnR must begin.

The main algorithm is contained in the while loop, which remains active as long as either the replacements are taking place or the entire source TextBox has been scanned.

In the next step, I used the InStr() library function that returns the position (integer) of the first occurance of the third argument in the second argument starting from the position specified by the first argument. The last-argument is used for the case sensitivity option.

The value returned by the InStr() function is received in FndPos. This value is greater than zero if the search string is found in the source text; non-zero otherwise. In the first part of the If - first statement places the result (replaced) in the SourceText variable. And, the next statement modifies the Cnt variable by FndPos + SearchTermLen. This is required because now the SnR must begin from the new position. On the other hand, in the Else part the Cnt variable is incremented by 1, indicating that the SnR must continue from the next character. The next few statements are used to display the result notifications to the user and are very simple to understand and implement. Just go through them and you will get an idea what they do.

Lastly, the function ReplaceFun() does the actual job of replacement. It picks up all the characters from the left of the Source until the position where the search string was found. Next, the result is appended with StringTBReplace, which is nothing but the string that is to be replaced with the source's matching. And at the last, all the remaing characters of the Source (exlcuding the one that was matched) are appended to it. The result is then returned.

The remaining functions/procedures do the job of formatting and UI enhancements and need not be explained.

Conclusion

There is no single method to efficiently code a logic. I believe that the approach I have used here is the most simple and strightforward. By using the demo project and/or source code, you will be able to implement "Search and Replace" in your application with maximum ease. However, bugs are likely to occur and I will try to rectify them as I find them.

Leftovers

If you are interested in implementing a "Search and Replace" that, instead of doing a "Replace All" does a "Replace One-by-One" or "Replace Once," you can do so by readjusting the code. You should stop the Replace operation immediately after first replace has been done. Extend the code and implement it as your own (by making the while loop terminate at the first replace).

Confession

I don't have a fully functional version of Visual Studio .NET on my PC (only the redistributable SDK), hence I don't have code ready for the same. I understand that Visual Basic 6 is pretty old and people are migrating to the .NET platform at a faster pace: however, I am sure that this article gave you a basic idea of implementing the SnR functionality in your applications. With this code as a skeleton (base), you will be able to develop your own SnR in .NET with greater ease.



Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • Agile methodologies give development and test teams the ability to build software at a faster rate than ever before. Combining DevOps with hybrid cloud architectures give teams not just the principles, but also the technology necessary to achieve their goals. By combining hybrid cloud and DevOps: IT departments maintain control, visibility, and security Dev/test teams remain agile and collaborative Organizational barriers are broken down Innovation and automation can thrive Download this white paper to …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds