Macros, in combination with Regular Expressions form a powerful tool set for generating code. This article will generate a Input Line Object from a VB6 Type Object. This a second in a series of articles on Code Generation utilizing Macros and Regular Expressions. To see the first article, click here.
In VB6, we often used the Type object (Structure in VB.NET) for defining the format of input files. Additionally, in VB6, a String could be defined as a fixed length; no longer supported in VB.NET. In .NET, using a little Macro wizardry, we can use the the old Type structure just long enough to assist us in creating an object-oriented approach to handling input records from a text file. The macro that I have written and demonstrate in this article will actually generate a whole class, including properties for each field in the original Type object. Additionally, the class will populate the properties without calling any methods in the Class.
Take the simple Type object shown below from a theoretical VB6 Application. We will assume that this object has not been processed by the Migration Wizard, otherwise the Type object would have been converted to a Structure and the string lengths would have been commented. If this had been done, then a simple modification to the Regular Expression, used in the Macro, would still use the string lengths to create the LineInputObject Class.
| Public Type Applicant Dim LastName As String * 25 Dim FirstName as String * 15 Dim Address As String * 25 Dim City as String * 15 Dim State As String * 2 Dim SSN As String * 11 Dim DOB as String * 10 End Type |
| 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 = "Private 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 stChar >= 1 AndAlso _" Const gf3 As String = " endChar >= stChar AndAlso _" Const gf4 As String = " dataLine.Length >= endChar AndAlso _" Const gf5 As String = " (endChar - stChar + 1) = Len _" Const gf6 As String = " Then" Const gf7 As String = _ " Return dataLine.Substring(stChar - 1, endChar - stChar + 1).Trim" Const gf8 As String = " Else" Const gf9 As String = _ " Throw New Exception(""GetField() bad input parameters"")" Const gf10 As String = "End If" Const gf11 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(" 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) 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 |
| Dim LastName As String * 25 Dim FirstName as String * 15 Dim Address As String * 25 Dim City as String * 15 Dim State As String * 2 Dim SSN As String * 11 Dim DOB as String * 10 |
| Public Class InputLineObject Private _LastName As String = String.Empty Private _FirstName As String = String.Empty Private _Address As String = String.Empty Private _City As String = String.Empty Private _State As String = String.Empty Private _SSN As String = String.Empty Public ReadOnly Property LastName() As String Get Return _LastName End Get End Property Public ReadOnly Property FirstName() As String Get Return _FirstName End Get End Property Public ReadOnly Property Address() As String Get Return _Address End Get End Property Public ReadOnly Property City() As String Get Return _City End Get End Property Public ReadOnly Property State() As String Get Return _State End Get End Property Public ReadOnly Property SSN() As String Get Return _SSN End Get End Property Private Sub Parse(ByVal line As String) LastName = GetField(line, 1, 25, 25) FirstName = GetField(line, 26, 40, 15) Address = GetField(line, 41, 65, 25) City = GetField(line, 66, 80, 15) State = GetField(line, 81, 82, 2) SSN = GetField(line, 83, 93, 11) End Sub Public Sub New(ByVal line As String) Parse(line) End Sub Private 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("GetField() bad input parameters") End If End Function End Class |
Dim sr As New IO.StreamReader(fileName) Dim line As String = String.Empty Do line = sr.ReadLine If line IsNot Nothing AndAlso line.Length > 0 Then Dim ilo As New InputLineObject(line) With ilo Dim firstName As String = .FirstName Dim lastName As String = .LastName ProcessApplicantName(firstName, lastName) ..... End With End If Loop |
| Ask a Question, or give your feedback on my articles or products by going to the KnowDotNet Forum or by clicking on My Blog. | ![]() |