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

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