Hack 79 Convert Field Codes to Text and Back Again When experimenting with fields, or using example fields culled from the Internet, it's often helpful to have an easy way to convert field codes to plain text, and vice versa.As the other hacks in this chapter show, it can be difficult to represent field codes outside of Word (such as in a printed book) because of those special field braces unique to Word. For example, what if you want to post a particularly troublesome field to a newsgroup in the hopes of finding some help? (For a list of web sites with Word-related information and discussion groups, see Where to Learn More in the Preface.) While it's relatively simple to convert a field's result to plain textjust select the field and press Ctrl-Shift-F9converting the field code to text is a trickier proposition. | A field's result is the text it displays after performing its work, such as the current page number or today's date. The field code is the special set of instructions a field uses to get that result. For example, one of the simplest field codes is simply DATE, which gets the current date. To see a field code in action, press Ctrl-F9 to insert a pair of empty field braces in a document. Then with your cursor between those braces, type the word DATE (you don't need to use all caps, but it's how field codes are typically shown). Select the field you just created and press F9 to update it, displaying today's date. |
| The macros in this hack use some heavy-duty VBA to quickly and accurately convert even a complex set of nested fields to plain text or convert some plain text (with the location of those special field braces indicated by regular braces) into fields.
8.11.1 Converting Field Codes into Plain Text Conceptually, you need to replace each field with just its code, surrounded by a set of regular text braces ({}). This is trickier than it sounds, because if a field has any other fields nested inside it, you need to convert those to text first.The code used in this hack to convert the fields to text is fairly simple, though it uses recursionone of VBA's more advanced features. Recursion means that a function can call itself, and it's a common feature among programming languages (see the sidebar A Recursion Primer for more information).
A Recursion Primer If you're not interested in how the guts of the macros in this hack work, or if you're already familiar with recursion, feel free to skip this sidebar. However, if you've never encountered recursion before or just aren't sure you understand it, read on.Recursion lets you use very simple code to perform complicated tasks. This is accomplished by breaking the task down into bite-sized pieces and then writing code that tackles the task, one small bite at a time until it's all gone.For example, say you need a macro to add all the digits from 1 to 4. At face value, it takes just one line:Sub SumDigits( ) MsgBox 1+2+3+4 End Sub But how do you write a macro that can sum all the digits from 1 to 1000 as easily as 1 to 10?Let's say you want your program to add all the digits from 1 to k, where k is any whole number. Here's one possible algorithm for the problem:If k is 1, then the answer is just k.If k is greater than 1, the answer is k plus the sum of all the digits from 1 to k - 1.So how do you calculate the sum of all the digits from 1 to k -1 in Step 2? Use your macro of course! Sound like a bit of circular logic? Well, in a way it is, which is the whole point of recursion. Here's that algorithm as a VBA procedure, followed by a macro to demonstrate it. Put both in the template of your choice and step through the code as it runs in Visual Basic EditorFunction SumDigits(k As Long) As Long If k = 1 Then SumDigits = k Else SumDigits = k + SumDigits(k - 1) End If End Function Sub SumDigitsDemo( ) Dim sInput As String sInput = InputBox("Add all digits from 1 to ?") If Len(sInput) = 0 Then Exit Sub MsgBox SumDigits(CLng(sInput)) End Sub | The following macro converts the field codes of any selected fields to plain text, and surrounds the code for each field with standard brace characters, ({}). The code use the FieldCodeToText function to recursively examine all the fields in a range (in this case the range of the current selection). Place both macros in the template of your choice.Sub ConvertSelectedFieldsToText( ) Call FieldCodeToText(Selection.Range) End Sub Function FieldCodeToText(rngOrig As Range) Dim rng As Range Do If rngOrig.Fields.Count <= 1 Then ' Not more than one field in selection, ' so replace first field in selection ' with its code surrounded by braces rngOrig.Text = "{" & _ rngOrig.Fields(1).Code.Text & "}" Else ' More than one field in selection, ' move to next field and check again, ' until there's only one field left Set rng = rngOrig.Duplicate rngOrig.Fields(2).Select Call FieldCodeToText(Selection.Range) rng.Select End If Loop Until rngOrig.Fields.Count = 0 End Function
8.11.2 Converting Plain Text into Fields For this conversion, the macro needs to do the reverse of what happened in the last section. This time around, any set of standard text braces ({}) and the text between them, should be replaced with a Word field. The field code is the text between the braces. The braces should be discarded.The following macro converts any plain text surrounded with standard brace characters ({}) into "live" Word fields. The code uses the TextToFieldCode function to ensure that all fields are created in the correct order, which can be tricky business when there are several nested fields. Place both macros in the template of your choice.Sub ConvertSelectedTextToFields( ) Call TextToFieldCodes(Selection.Range) End Sub Function TextToFieldCodes(rngOrig As Range) Dim rng As Range Dim fld As Field Dim str As String Do Set rng = rngOrig.Duplicate str = rng.Text ' If there are any braces remaining in the range, except ' for the first and last characters, then there's still ' some pseuodo-fields to process, so collapse range to ' next set of braces and check again If InStr(Mid(str, 2, Len(str) - 2), "}") <> 0 Or _ InStr(Mid(str, 2, Len(str) - 2), "{") <> 0 Then ' Move the beginning of the range forward ' until it's at a left brace Do While InStr(Right(str, Len(str) - 1), "{") > 0 rng.MoveStart unit:=wdCharacter, Count:=1 rng.MoveStartUntil cset:="{" str = rng.Text Loop ' Move the end of the range backward until it's at a right brace Do While InStr(Left(str, Len(str) - 1), "}") > 0 rng.MoveEnd unit:=wdCharacter, Count:=-1 rng.MoveEndUntil cset:="}", Count:=-Len(str) str = rng.Text Loop ' If either end of the range isn't a brace character, ' there's been an error. If Left(str, 1) <> "{" Or Right(str, 1) <> "}" Then GoTo ERR_HANDLER End If ' Continue searching for brace characters in this range ' with a recursive call to this function Call TextToFieldCodes(rng) Else ' No brace characters were found between ' the first and last characters ' If either end of the range isn't a brace character, ' there's been an error. If Left(str, 1) <> "{" Or Right(str, 1) <> "}" Then GoTo ERR_HANDLER End If ' Delete the braces on the ends of the range rng.Characters(1).Delete rng.Characters(rng.Characters.Count).Delete ' Cut the range and paste it in as the code ' of a new empty field, which preserves any ' codes in the range, as well as formatting rng.Cut Set fld = rng.Fields.Add(Range:=rng, _ Type:=wdFieldEmpty, _ Text:=", _ PreserveFormatting:=False) fld.Code.Paste End If ' As long as there are braces left in the original range, ' keep trying to turn them into fields Loop While InStr(rngOrig.Text, "}") <> 0 Or _ InStrRev(rngOrig.Text, "{") <> 0 Exit Function ERR_HANDLER: rng.Select If Left(rng.Text, 1) <> "{" Then MsgBox "Missing an expected left brace ( { )", vbCritical ElseIf Right(rng.Text, 1) <> "}" Then MsgBox "Missing an expected right brace ( } )", vbCritical Else MsgBox "An unknown error occurred", vbCritical End If End Function
8.11.3 Running the Hack To see these macros in action, first make sure the template you've stored them in is open. Then, in a blank document based on the template in which you've stored the macros, type Ctrl-F9 twice to insert two sets of field braces, one nested inside the other (you'll see actual field braces, not standard text braces):{ { } } Type the text QUOTE and DATE between the field braces as follows:{ QUOTE { DATE } } Next, select the fields and press F9. You should see today's date displayed. Select the fields again, then right-click and select Toggle Field Codes. Now you'll see the field codes again. With both fields selected, run the ConvertSelectedFieldsToText macro shown earlier, which replaces the fields with their field codes as plain text, surrounded by standard text braces.Now select the text from the first brace to the last and run the ConvertSelectedTextToFields macro shown earlier, which replaces the plain text with actual fields, bringing you back to where you started. |