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