WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Hacking Word
Pages: 1, 2, 3, 4, 5

moderate

Hack #55: Clean Out Linked “Char” Styles

Documents created or edited in Word 2002 or 2003 have a nasty habit of sprouting hidden character styles that are hard to see, let alone eliminate. This hack shows you how to lead a “Char-free” life with Word.



In most programs that offer style-based formatting (such as InDesign, FrameMaker, or QuarkXPress), if you try to apply a paragraph style to just part of a paragraph, the entire paragraph is modified to reflect the new style. But in Word, things aren’t so simple. In older versions of Word, when you apply a paragraph style to only part of a paragraph, the paragraph retains its original style, but the selected text takes on the character formatting of the paragraph style you tried to apply. That introduces a lot of direct formatting into documents, which can make them difficult to modify and maintain.

WARNING: Apply paragraph styles only with all or none—never some—of the paragraph selected to avoid this “feature.”

Starting in Word 2002, rather than just applying the character formatting of the paragraph style, Word creates a new, hidden character style based on the paragraph style and tacks the word “Char” on the end, such as “Heading 1 Char.”

Ostensibly, this is an improvement of the behavior of earlier versions of Word. Rather than changing Word to behave like other programs (and thus encouraging the conscientious use of character styles), Microsoft changed Word to behave in a strange, new, and—surprise!—poorly documented way. Because the Char styles are linked to the paragraph styles on which they’re based, if you later change the paragraph style, the character style also changes.

Spotting Char Styles

To see these bizarre styles in action (assuming you are using a newer version of Word), open a new document and drop in a few paragraphs of placeholder text [Hack #14].

Now select a word or two within one of the paragraphs and apply the “Heading 1” style to the selection. Check your styles, either using the Task Pane or the Styles pull-down menu on the Formatting toolbar. See anything amiss? Well, that’s a trick question. There are two things amiss, but you won’t see them right away on the Styles pull-down menu or the Task Pane:

  • Word created a new character style based on the formatting properties of the “Heading 1” style.
  • Word has not told you about this new style, which, as you’ve discovered, doesn’t appear with the other styles in the usual places.

Now, hold down the Shift key and click on the Styles pull-down menu on the Formatting toolbar. Scroll down to the “H” section, as shown in Figure 6-8, and you’ll see the new style. You can also view the linked style from the Reveal Formatting Task Pane.

Figure 6-8. The elusive Char style
Figure 6-8. The elusive Char style

You can work in a document for weeks and never notice these styles. However, if you send your document to someone using an older version of Word that doesn’t support these “linked styles,” they’ll appear right away in the Styles pull-down menu and the Styles and Formatting dialog.

Once you cut and paste the styles around your document, among different documents, and back and forth across different versions of Word, something even stranger happens. They evolve. Mutate. Fester. Until your document is rife with monstrosities like the following:

  Body Text Char Char, Body Text Char1 Char Char, Body Text Char Char

Sometimes the “Char” extension even gets added to some of your paragraph styles. Does the fun ever stop?

Unfortunately, you can’t prevent Word from creating these styles. And even if you still use Word 2000, these styles will show up in documents worked on by Word 2002 and 2003 users.

The situation gets even stranger when you try to delete these styles. In Word 2000, you at least stand a chance. Since 2000 doesn’t have linked styles, you can rename or delete them as needed, just like any other style. But in Word 2002 and 2003—the source of these bizarre styles—you aren’t so lucky. When you try to delete “Heading 1 Char,” the silence is deafening. Nothing. Not even a dialog admonishing your efforts.

So maybe you should try a little VBA? Running the following code in the Immediate window [Hack #2] would seem to be a solution:

  ActiveDocument.Styles("Heading 1 Char").Delete

When you run the code, the dialog shown in Figure 6-9 greets you. But take a look at your document again—the style’s gone.

Figure 6-9. Deleting the linked style generates a runtime error
Figure 6-9. Deleting the linked style generates a runtime error

What’s going on here? For a clue, try the following code in the Immediate window:

  ActiveDocument.Styles("Heading 1").Delete

You get your old friend, Runtime Error 4198.

Remember, the styles are linked. If you change one, you change both—and that goes for deletion as well. However, you can’t delete a built-in style, which is why you’re greeted with Runtime Error 4198 (and why nothing happened when you tried to delete it from within Word).

So what if you repeat this with a Char style not based on one of Word’s built-ins? Then there’s nothing stopping Word from deleting both styles and removing all of the formatting from any text that used them. Yikes! Fortunately, there’s a fix. With the code in this hack, you can quickly clear out any linked Char styles in your document, without losing any other styles.

The Code

This code will delete any character style with the word “Char” in it and remove the word “Char” from the name of any paragraph style. Since deleting a linked style also deletes any style it’s linked to, the link must first be broken (which is accomplished by linking it to, ironically, the Normal style).

TIP: This macro deletes character styles from your document. You will lose any formatting applied to text using the deleted character styles. If you want to keep the character formatting, see the upcoming section “Hacking the Hack.”

Because Word 2000 (and Word 97) doesn’t have a LinkStyle property for styles, if you’re using that version of Word, this code will not run unless you comment out one line, as noted within the code. Note that there are two procedures here: the main DeleteCharCharStyles macro and a supporting function named SwapStyles. Both are needed for this hack to work.

Sub DeleteCharCharStyles( )
Dim sty As Style
Dim i As Integer
Dim doc As Document
Dim sStyleName As String
Dim sStyleReName As String
Dim bCharCharFound As Boolean

Set doc = ActiveDocument
Do
    bCharCharFound = False
    For i = doc.Styles.Count To 1 Step -1
        Set sty = doc.Styles(i)
        sStyleName = sty.NameLocal
        If sStyleName Like "* Char*" Then
            bCharCharFound = True
            If sty.Type = wdStyleTypeCharacter Then
            On Error Resume Next
           '#############################################
           ' COMMENT OUT THE NEXT LINE IN WORD 2000 OR 97
           sty.LinkStyle = wdStyleNormal
           sty.Delete
           Err.Clear
        Else
           sStyleReName = Replace(sStyleName, " Char", "")
           On Error Resume Next
           sty.NameLocal = sStyleReName
           If Err.Number = 5173 Then
              Call SwapStyles(sty, doc.Styles(sStyleReName), doc)
              sty.Delete
              Err.Clear
           Else
             On Error GoTo ERR_HANDLER
           End If
         End If
         Exit For
      End If
      Set sty = Nothing
    Next i
  Loop While bCharCharFound = True
  Exit Sub
  ERR_HANDLER:
  MsgBox "An Error has occurred" & vbCr & _
          Err.Number & Chr(58) & Chr(32) & Err.Description, _
          vbExclamation
  End Sub
  
  Function SwapStyles(ByRef styFind As Style, _
                      ByRef styReplace As Style, _
                      ByRef doc As Document)
  With doc.Range.Find
       .ClearFormatting
       .Text = ""

       .Wrap = wdFindContinue
       .MatchCase = False
       .MatchWholeWord = False
       .MatchWildcards = False
       .MatchSoundsLike = False
       .MatchAllWordForms = False
       .Style = styFind
       .Replacement.ClearFormatting
       .Replacement.Style = styReplace
       .Replacement.Text = "^&"
       .Execute Replace:=wdReplaceAll
     End With
     End Function

The second procedure, SwapStyles, is there because of a scenario that often occurs when documents that have these linked styles go back and forth between different versions of Word. Often, what started as one paragraph style—for example, Sidebar—may have mutated into two paragraph styles, such as:

  • Sidebar
  • Sidebar Char Char

In that situation, if the code just tries to remove the “Char” strings from the second Sidebar style, an error will be raised because the name Sidebar is already taken. With the SwapStyles procedure, all the text formatted with the second style is modified and formatted with the first, and then the second style is simply deleted.

Running the Hack

After you put both procedures in the template of your choice [Hack #50], and either run it from the Tools -> Macro -> Macros dialog or put a button for it on a menu or toolbar [Hack #1].

This code affects only styles with the string “ Char”, including the leading space. If you plan to use this macro to clean your documents, you should avoid deliberately using the string “ Char” in any of your styles. However, feel free to begin a style name with Char, as in “CharacterStyleNumberOne.”

Hacking the Hack

If you want to delete the linked Char styles but retain the character formatting on the text, use this version of the code. It includes an additional procedure, StripStyleKeepFormatting, that removes the character style applied to the text but retains the formatting defined by that style. Again, if you use an earlier version of Word, you’ll need to comment out the line that unlinks the character style, as noted in the code.


  Sub DeleteCharCharStylesKeepFormatting( )
  Dim sty As Style
  Dim i As Integer
  Dim doc As Document
  Dim sStyleName As String
  Dim sStyleReName As String
  Dim bCharCharFound As Boolean
  
  Set doc = ActiveDocument
  Do
  
      bCharCharFound = False
      For i = doc.Styles.Count To 1 Step -1
          Set sty = doc.Styles(i)
          sStyleName = sty.NameLocal
          If sStyleName Like "* Char*" Then
 
          bCharCharFound = True
          If sty.Type = wdStyleTypeCharacter Then
          Call StripStyleKeepFormatting(sty, doc)
          On Error Resume Next
          '#############################################
          ' COMMENT OUT THE NEXT LINE IN WORD 2000 OR 97
          sty.LinkStyle = wdStyleNormal
          sty.Delete
          Err.Clear
      Else
          sStyleReName = Replace(sStyleName, " Char", "")
          On Error Resume Next
          sty.NameLocal = sStyleReName
          If Err.Number = 5173 Then
             Call SwapStyles(sty, doc.Styles(sStyleReName), doc)
             sty.Delete
          Err.Clear
        Else
          On Error GoTo ERR_HANDLER
        End If
      End If
      Exit For
    End If
    Set sty = Nothing
   Next i
 Loop While bCharCharFound = True
 Exit Sub
ERR_HANDLER:
MsgBox "An Error has occurred" & vbCr & _
        Err.Number & Chr(58) & Chr(32) & Err.Description, _
        vbExclamation
End Sub

Function SwapStyles(ByRef styFind As Style, _
                    ByRef styReplace As Style, _
                    ByRef doc As Document)
With doc.Range.Find
     .ClearFormatting
     .Text = ""
     .Wrap = wdFindContinue
     .MatchCase = False
     .MatchWholeWord = False
     .MatchWildcards = False
     .MatchSoundsLike = False
     .MatchAllWordForms = False
     .Style = styFind
     .Replacement.ClearFormatting
     .Replacement.Style = styReplace
     .Replacement.Text = "^&"
     .Execute Replace:=wdReplaceAll
  End With
End Function


Function StripStyleKeepFormatting(ByRef sty As Style, _
                                  ByRef doc As Document)
Dim rngToSearch As Range
Dim rngResult As Range
Dim f As Font

Set rngToSearch = doc.Range
Set rngResult = rngToSearch.Duplicate

Do
    With rngResult.Find
    .ClearFormatting
    .Style = sty
    .Text = ""
    .Forward = True
    .Wrap = wdFindStop
    .Execute
   End With

   If Not rngResult.Find.Found Then Exit Do
  
   Set f = rngResult.Font.Duplicate
   With rngResult
        .Font.Reset
        .Font = f
        .MoveStart wdWord
        .End = rngToSearch.End
   End With
   Set f = Nothing
Loop Until Not rngResult.Find.Found
End Function

 
TIP: For an alternative method, check out “Remove Linked “Char” Styles with XSLT” [Hack #98].

Pages: 1, 2, 3, 4, 5

Next Pagearrow