Clean Out Linked "Char" Styles





Clean Out Linked "Char" Styles

figs/moderate.gif figs/hack55.gif

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.

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.

1 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, and you'll see the new style. You can also view the linked style from the Reveal Formatting Task Pane.

The elusive Char style
figs/wrdh_0608.gif


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 greets you. But take a look at your document again—the style's gone.

Deleting the linked style generates a runtime error
figs/wrdh_0609.gif


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.

2 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).

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 Section 6.6.4.


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.

3 Running the Hack

After you put both procedures in the template of your choice [Hack #50], and either run it from the ToolsMacroMacros 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."

4 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

For an alternative method, check out [Hack #98] .



     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows