Search and Replace with Regular Expressions

Introduction

Ice-cream is exquisite—what a pity it isn’t illegal.
—Voltaire

Neither male or female parents are superfluous. Parents teach children things implicitly by their habits and sometimes explicitly when the kids are listening. Sometimes, a parent has a bad habit; the child sees the consequences and says “I don’t want that bad thing to happen to me!” Sometimes, the reverse is true. Both kinds of lessons are valuable and different genders seem to have different habits.

One overt lesson my dad taught me was that a craftsman is known by his tools. Of all of the things he said to me, I don’t know why this resonated so much with me, but hey, I’ll take it.

Software development is a parable of the craftsman’s tools. It was Arthur C. Clarke who said that “any sufficiently advanced technology is indistinguishable from magic.” I will extend that and add that the more you know about your technology, trade, and tools, the more likely it is that you will do magical things.

In this article, I have taken a pedestrian subject—finding and finding and replacing code—and will add a twist. If you finish the article, you will know how to combine regular expressions with Visual Studio’s Quick Find and Quick Replace capability to augment plain searching and replacing and Refactoring, adding to your ability to do magic.

Before You Get Started…

Ctrl + F and Ctrl +H—at least that’s the way my keyboard is mapped invoke the Edit|Find and Replace|Quick Find and Quick Replace feature of Visual Studio. Type in some text and Visual Studio will search the current file, project, or solution for the text. Choose the Quick replace option and Visual studio will replace the found text with the replacement text. This is probably the most common kind of search and replace operation performed routinely by developers.

There is another meta-programming capability built into Visual Studio called Refactoring that will transform code from one thing to something else, including renaming something. Refactoring stems from a 1990 thesis by William Opdike and is essentially a formalized way to clean up or improve code.

Mix in search and replace, Refactoring, and simple copy and paste, and you have three ways to change code. Refactoring to neophytes is the closest thing to magic of the three. The problem is that none of these handle special cases such as searching and replacing across line feeds or handling varying styles of white space {for example, space versus tab} in a uniform way. Refactoring is mostly limited to known ways to improve code like renaming, copy and paste is tedious, and search and replace all may overwrite things you don’t want overwritten, thus making search and replace sometimes a long, tedious process too.

So, look at a fourth way to find things, a way that permits substantially more expressiveness and preciseness, Regular Expressions.

If the Code is Funky, Change It

Many programmers are precisely old enough to have learned their coding standards implicitly from Charles Simonyi whether they know it or not. Simonyi is attributed with inventing the Hungarian notation—those ghastly prefixes that are everywhere in VB code. Alas, Dr. Simonyi is out to pasture and is spending his hard-earned money flying on Russian spaceships, sailing gigantic yachts, and dating Martha Stewart?! I don’t want to get sued so I won’t say anything about potential problems manifest in anyone’s hardwiring, but I will say that I feel about dating Martha Stewart the same way I feel about the Hungarian notation or any variation of it. (Although Martha could organize my house any time she likes.)

So, anti-establishment, anti-notation wonks like me might write the code in Listing 1. I use a simple F for field prefix simply to distinguish field names from property names. F-prefixes are very easy to remember, it means field—to me—and no other prefix is necessary, anywhere.

The point is that sometimes we get valuable code from third parties and those other parties’ styles do not match our own or the desired style. Rather than fret over so small a thing, simply change the code. (That’s my scenario, humble as it is, and I am sticking to it!)

Listing 1: Found some code that doesn’t fit your style? Instead of having coding standards meetings or getting all worked up, simply change the code.

Imports System.Data.Linq
Imports System.Data.Linq.Mapping
Imports System.Reflection
Imports System.Text


Module Module1

   Sub Main()

      Const connectionString As String = _
         "Data Source=.SQLEXPRESS;AttachDbFilename=c:temp _
            northwnd.mdf;" + _
         "Integrated Security=True;Connect Timeout=30; _
            User Instance=True"

      Dim northwind As Northwind = New Northwind(connectionString)
      Dim customers As Table(Of Customer) = _
         northwind.GetTable(Of Customer)()

      Dim firstFive = customers.Take(5)
      For Each item In firstFive
         Console.WriteLine(item)
      Next
         Console.ReadLine()
   End Sub

End Module

Public Class Northwind
   Inherits DataContext

   Public Sub New(ByVal connectionString As String)
      MyBase.New(connectionString)
      Me.Log = Console.Out
   End Sub

End Class

<Table(Name:="Customers")> _
PublicClass Customer

   Private FCustomerID As String
   Private FCompanyName As String
   Private FContactName As String
   Private FContactTitle As String
   Private FAddress As String
   Private FCity As String
   Private FRegion As String
   Private FPostalCode As String
   Private FCountry As String
   Private FPhone As String
   Private FFax As String

   <Column(Name:="CustomerID", Storage:="FCustomerID")> _
   Public Property CustomerID() As String
      Get
         Return FCustomerID
      End Get
      Set(ByVal value As String)
         FCustomerID = value
      End Set
    End Property

   <Column(name:="CompanyName", Storage:="FCompanyName")> _
      Public Property CompanyName() As String
      Get
         Return FCompanyName
      End Get
      Set(ByVal value As String)
         FCompanyName = value
      End Set
   End Property

   <Column(name:="ContactName", Storage:="FContactName")> _
   Public Property ContactName() As String
      Get
         Return FContactName
      End Get
      Set(ByVal value As String)
         FContactName = value
      End Set
   End Property

   <Column(name:="ContactTitle", Storage:="FContactTitle")> _
      Public Property ContactTitle() As String
      Get
         Return FContactTitle
      EndGet
      Set(ByVal value As String)
         FContactTitle = value
      End Set
   End Property

   <Column(name:="Address", Storage:="FAddress")> _
      Public Property Address() As String
      Get
         Return FAddress
      End Get
      Set(ByVal value As String)
         FAddress = value
      End Set
   End Property

   <Column(name:="City", Storage:="FCity")> _
      Public Property City() As String
      Get
         Return FCity
      End Get
      Set(ByVal value AsString)
         FCity = value
      End Set
   End Property

   <Column(name:="Region", Storage:="FRegion")> _
      Public Property Region() As String
      Get
         Return FRegion
      End Get
      Set(ByVal value As String)
         FRegion = value
      End Set
   End Property

   <Column(name:="PostalCode", Storage:="FPostalCode")> _
      Public Property PostalCode() As String
      Get
         Return FPostalCode
      End Get
      Set(ByVal value As String)
         FPostalCode = value
      End Set
   End Property

   <Column(name:="Country", Storage:="FCountry")> _
      Public Property Country() As String
      Get
         Return FCountry
      End Get
      Set(ByVal value As String)
         FCountry = value
      End Set
   End Property

   <Column(name:="Phone", Storage:="FPhone")> _
      Public Property Phone() As String
      Get
         Return FPhone
      End Get
      Set(ByVal value As String)
         FPhone = value
      End Set
   End Property

   <Column(name:="Fax", Storage:="FFax")> _
      Public Property Fax() As String
      Get
         Return FFax
      End Get
      Set(ByVal value As String)
         FFax = value
      End Set
   End Property

   Public Overrides Function ToString() As String

      Dim builder As StringBuilder = New StringBuilder()
      builder.AppendFormat("{0}", Me.GetType().Name)
      builder.AppendLine()
      builder.AppendFormat("{0}", New String("-", 40))
      builder.AppendLine()

      Dim info() As PropertyInfo = Me.GetType().GetProperties()

      For Each prop In info
         Try
            Dim value As Object = prop.GetValue(Me, Nothing)
            builder.AppendFormat("{0}: {1}", prop.Name, value)
         Catch ex As Exception
            builder.AppendFormat("{0}: {1}", prop.Name, "None")
         End Try
         builder.AppendLine()
      Next

      Return builder.ToString()
   End Function


End Class

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read