Would you like to be able to generate a Class with hundreds of lines of Bug-Free code without buying a third-party tool? This article will show you how to do it with a Macro. When someone mentions Extensibility, Automation, or Add-Ins, some developers have never bothered to investigate the power associated with these terms. When I showed a developer a Macro recently, he said, "I used to write Macros", and looked as if he had moved past that phase of his .NET experience. But, actually, Macros are a great tool for generating large blocks of bug-free code. In this article I am going to show you a macro that will generate an entire complete class to process an input row from a fixed-length field data file. I often use this type of object in processing fixed field input files.
Remember the Type Statement in VB6? It has now been replaced by the Structure statement in VB.NET. But in VB6, we often used the Type Statement to define record layouts. In the Type, as shown below, we also used fixed length strings to define the length of input and output fields.
Figure 1 - VB6 Type Definition.
| Type InputRecord RecordId As String * 2 LastName As String * 15 FirstName As String * 25 MiddleName As String * 15 Address1 As String * 35 Address2 As String * 35 City As String * 25 State As String * 25 Zip As String * 10 HomePhone As String * 12 WorkPhone As String * 12 EmailAddress As String * 50 LicenseNumber As String * 15 DLState As string * 2 End Type |
| Public Class InputRecord Private _RecordId As String = String.Empty Private _LastName As String = String.Empty Private _FirstName As String = String.Empty Private _MiddleName As String = String.Empty Private _Address1 As String = String.Empty Private _Address2 As String = String.Empty Private _City As String = String.Empty Private _State As String = String.Empty Private _Zip As String = String.Empty Private _HomePhone As String = String.Empty Private _WorkPhone As String = String.Empty Private _EmailAddress As String = String.Empty Private _LicenseNumber As String = String.Empty Public Property RecordId() As String Get Return _RecordId End Get Set(ByVal Value As String) _RecordId = Value End Set End Property Public Property LastName() As String Get Return _LastName End Get Set(ByVal Value As String) _LastName = Value End Set End Property Public Property FirstName() As String Get Return _FirstName End Get Set(ByVal Value As String) _FirstName = Value End Set End Property Public Property MiddleName() As String Get Return _MiddleName End Get Set(ByVal Value As String) _MiddleName = Value End Set End Property Public Property Address1() As String Get Return _Address1 End Get Set(ByVal Value As String) _Address1 = Value End Set End Property Public Property Address2() As String Get Return _Address2 End Get Set(ByVal Value As String) _Address2 = Value End Set End Property Public Property City() As String Get Return _City End Get Set(ByVal Value As String) _City = Value End Set End Property Public Property State() As String Get Return _State End Get Set(ByVal Value As String) _State = Value End Set End Property Public Property Zip() As String Get Return _Zip End Get Set(ByVal Value As String) _Zip = Value End Set End Property Public Property HomePhone() As String Get Return _HomePhone End Get Set(ByVal Value As String) _HomePhone = Value End Set End Property Public Property WorkPhone() As String Get Return _WorkPhone End Get Set(ByVal Value As String) _WorkPhone = Value End Set End Property Public Property EmailAddress() As String Get Return _EmailAddress End Get Set(ByVal Value As String) _EmailAddress = Value End Set End Property Public Property LicenseNumber() As String Get Return _LicenseNumber End Get Set(ByVal Value As String) _LicenseNumber = Value End Set End Property Private Sub Parse(ByVal line As String) RecordId = GetField(line, 1, 2, 2) LastName = GetField(line, 3, 17, 15) FirstName = GetField(line, 18, 42, 25) MiddleName = GetField(line, 43, 57, 15) Address1 = GetField(line, 58, 92, 35) Address2 = GetField(line, 93, 127, 35) City = GetField(line, 128, 152, 25) State = GetField(line, 153, 177, 25) Zip = GetField(line, 178, 187, 10) HomePhone = GetField(line, 188, 199, 12) WorkPhone = GetField(line, 200, 211, 12) EmailAddress = GetField(line, 212, 261, 50) LicenseNumber = GetField(line, 262, 276, 15) End Sub Public Sub New(ByVal line As String) Parse(line) End Sub Public Function GetField(ByVal dataLine As String, _ ByVal stChar As Integer, ByVal endChar As Integer, _ ByVal len As Integer) As String If dataLine.Length < 205 Then dataLine += Space(205 - dataLine.Length) If stChar >= 1 AndAlso _ endChar <= 205 AndAlso _ endChar >= stChar AndAlso _ dataLine.Length >= endChar AndAlso _ (endChar - stChar + 1) = Len _ Then Return dataLine.Substring(stChar - 1, endChar - stChar + 1).Trim Else Throw New Exception("ServiceRequests: GetField() bad input parameters") End If End Function End Class |
| Dim inputRec As InputRecord Using sr As New System.IO.StreamReader(fileName) Dim line As String = sr.ReadLine() inputRec = New InputRecord(line) With inputRec Dim firstName As String = inputRec.FirstName Dim lastName As String = inputRec.LastName '... use similiar code to retrieve the remainder of the fields ' process the input End With End Using |
| Public Sub CreateInputObjectMethod() Dim ts As TextSelection = DTE.ActiveDocument.Selection Dim s As String = ts.Text Dim mc As MatchCollection = Regex.Matches(s, _ "^\s*(?<field>\w+)\s+As\s+String\s+\*\s+(?<nbr>\d+)", RegexOptions.Multiline) Dim cnt As Integer = 0 Dim stPtr As Integer = 1 Dim sb As New Text.StringBuilder(5000) Dim sbpriv As New Text.StringBuilder(5000) Dim sbprop As New Text.StringBuilder(5000) Dim sbClass As New Text.StringBuilder(5000) Const gf1 As String = _ "Public Function GetField(ByVal dataLine As String, " & _ "ByVal stChar As Integer, ByVal endChar As Integer, " & _ "ByVal len As Integer) As String" Const gf2 As String = _ " If dataLine.Length < 205 Then dataLine += Space(205 - dataLine.Length)" Const gf3 As String = " If stChar >= 1 AndAlso _" Const gf4 As String = " endChar <= 205 AndAlso _" Const gf5 As String = " endChar >= stChar AndAlso _" Const gf6 As String = " dataLine.Length >= endChar AndAlso _" Const gf7 As String = " (endChar - stChar + 1) = Len _" Const gf8 As String = " Then" Const gf9 As String = _ " Return dataLine.Substring(stChar - 1, endChar - stChar + 1).Trim" Const gf10 As String = " Else" Const gf11 As String = _ " Throw New Exception(""ServiceRequests: GetField() bad input parameters"")" Const gf12 As String = "End If" Const gf13 As String = "End Function" Dim name As String = InputBox("Enter name for new Input Object", "Enter Object Name", "") If name.Length > 0 Then sbClass.Append("Public Class " & name & vbCrLf) sb.Append(" Private Sub Parse(Byval line As String)" & vbCrLf) For Each m As Match In mc Dim nbr As Integer = CType(m.Groups("nbr").Value, Integer) cnt += nbr ' create the private var for each match sbpriv.Append(" Private _" & m.Groups("field").Value & _ " As String = String.Empty" & vbCrLf) ' create the matching property sbprop.Append(" Public Property " & _ m.Groups("field").Value & "() As String" & vbCrLf) sbprop.Append(" Get" & vbCrLf) sbprop.Append(" Return _" & m.Groups("field").Value & vbCrLf) sbprop.Append(" End Get" & vbCrLf) sbprop.Append(" Set(ByVal Value As String)" & vbCrLf) sbprop.Append(" _" & m.Groups("field").Value & " = Value" & vbCrLf) sbprop.Append(" End Set" & vbCrLf) sbprop.Append(" End Property" & vbCrLf) sb.Append(m.Groups("field").Value & " = GetField(line, " & _ stPtr.ToString & ", " & cnt & ", " & _ m.Groups("nbr").Value & ")" & vbCrLf) stPtr += nbr Next sb.Append(" End Sub" & vbCrLf) sb.Append(" Public Sub New(Byval line As String)" & vbCrLf) sb.Append(" Parse(line)" & vbCrLf) sb.Append(" End Sub" & vbCrLf) sb.Append(gf1 & vbCrLf) sb.Append(gf2 & vbCrLf) sb.Append(gf3 & vbCrLf) sb.Append(gf4 & vbCrLf) sb.Append(gf5 & vbCrLf) sb.Append(gf6 & vbCrLf) sb.Append(gf7 & vbCrLf) sb.Append(gf8 & vbCrLf) sb.Append(gf9 & vbCrLf) sb.Append(gf10 & vbCrLf) sb.Append(gf11 & vbCrLf) sb.Append(gf12 & vbCrLf) sb.Append(gf13 & vbCrLf) Debug.WriteLine(sb.ToString) DTE.ItemOperations.NewFile("General\Text File") sbClass.Append(sbpriv.ToString() & vbCrLf) sbClass.Append(sbprop.ToString() & vbCrLf) sbClass.Append(sb.ToString() & vbCrLf) sbClass.Append("End Class" & vbCrLf) DTE.ActiveDocument.Object("TextDocument"). _ Selection.Insert(sbClass.ToString) End If End Sub |
| Ask a Question, or give your feedback on my articles or products by going to the KnowDotNet Forum or by clicking on My Blog. | ![]() |