View Single Post
 
Old 11-25-2018, 04:29 AM
David.Lee David.Lee is offline Windows 7 32bit Office 2016
Novice
 
Join Date: Nov 2018
Posts: 7
David.Lee is on a distinguished road
Default

Thanks for helping. What do you mean by adding the reference to Scripting.Runtime?

Code:
Option Explicit

Public Const open_smart_quote As String = "“"                       ' Smart quote entered using ALT+0147
Public Const not_open_smart_quote As String = "([!“])"
Public Const close_smart_quote As String = "”"                      ' Smart quote entered using ALT+0148
Public Const capitalised_word As String = "([A-Z])(*)"              ' Any sequence of characters starting with a Capital letter
Public Const end_of_capitalised_word As String = "([^13 ,.-:;])"    ' Possible characters that end a definition if closing smart quote omitted
Public Const breaking_space As String = " "
Public Const lcase_letters As String = "abcdefghijklmnopqrstuvwxyz"
Public Const ucase_letters As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

Public search_doc As Word.Document
Public quoted_definitions As Scripting.Dictionary

Sub annotate_definitions_in_a_doc()

    Set search_doc = ActiveDocument
    Set quoted_definitions = New Scripting.Dictionary
    compile_list_of_quoted_definitions
    check_that_definitions_are_used
    highlight_unused_definitions
    highlight_capitalised_phrases_with_no_definition
    
End Sub

Sub compile_list_of_quoted_definitions()

Dim search_range As Word.Range

    Set search_range = search_doc.StoryRanges(wdMainTextStory)

    With search_range.Find
        .ClearFormatting
        .Replacement.ClearFormatting
        .MatchWildcards = True
        .Wrap = wdFindStop
        .Text = open_smart_quote & capitalised_word & end_of_capitalised_word
        .Execute
        Do Until search_range.Text = vbNullString
            update_search_range_to_whole_capitalised_phrase search_range
            update_search_range_to_capitalised_phrase_text search_range
            do_actions_for_quoted_text search_range
            search_range.Move unit:=wdWord
            .Execute
        Loop
    End With
   
End Sub

Sub do_actions_for_quoted_text(this_range As Word.Range)

    ' Check to see if a definition we have just found already exists
    If quoted_definitions.Exists(this_range.Text) Then
        search_doc.Comments.Add Range:=this_range, Text:="Duplicate definition?"
        Exit Sub
    End If

    If Not this_range.Next(unit:=wdCharacter).Text = close_smart_quote Then
        ' comment out the line below if you don't want comments in the document
        search_doc.Comments.Add Range:=this_range.Duplicate, Text:="Missing closing quote"
        ' Uncomment the next line to add a closing smart quote if one is missing.
        ' this_range.InsertAfter Text:=close_smart_quote
    End If
    
    quoted_definitions.Add Key:=this_range.Text, Item:=True
    
End Sub

Sub update_search_range_to_whole_capitalised_phrase(this_range As Word.Range)
    ' We didn't include the close_smart_quote in the search but if present
    ' it will be the second to last charcter in the search range
    ' so we will only extend the range if no close_smart_quote is present in this_range.text
    If InStr(this_range.Text, close_smart_quote) = 0 Then
        ' The last character of this_range will be a character from end_of_capitalised_word.
        ' We only want to extend the range if the last character is a breaking_space
        ' Two seperate if statemdnts are used because this provides greater flexibility
        ' if we need to make tweaks later on.
        If this_range.Characters.Last.Text = breaking_space Then
            Do While InStr(ucase_letters, this_range.Next(unit:=wdWord).Characters.First.Text) > 0
                this_range.MoveEnd unit:=wdWord, Count:=1
            Loop
        End If
    End If
    
End Sub

Sub update_search_range_to_capitalised_phrase_text(this_range As Word.Range)
    ' This subroutine is used on two occasions with slightly different requirements
    ' consequently we test for the relevant characters before adjusting the range
    ' as in the second use the characters definitiely won't be included in the range
    
    If this_range.Characters.First.Text = open_smart_quote Then
        this_range.MoveStart unit:=wdCharacter, Count:=1              ' Eliminate the start_smart_quote
    End If
    ' check if they are present before adjusting the end of the range.
    If InStr(end_of_capitalised_word, this_range.Characters.Last.Text) > 0 Then
        this_range.MoveEnd unit:=wdCharacter, Count:=-1               ' Eliminate the terminating character
    End If
    If this_range.Characters.Last.Text = close_smart_quote Then
        this_range.MoveEnd unit:=wdCharacter, Count:=-1           ' If present remove the close_smart_quote
    End If
    ' this_range should now encompass only the text of the definition

End Sub
    
Sub check_that_definitions_are_used()

Dim definition As Variant
Dim search_range As Word.Range

    ' We can now use the scripting.dictionary of defined terms to check if they
    ' actually occur in the document
    ' if we don't find a definition used in the document then the item value
    ' of the definition in the dictionary will be set to false.
    
    For Each definition In quoted_definitions.keys
        Set search_range = search_doc.StoryRanges(wdMainTextStory)
    
        With search_range.Find
            .ClearFormatting
            .Replacement.ClearFormatting
            .MatchWildcards = True
            .MatchCase = True
            .Wrap = wdFindStop
            .Text = not_open_smart_quote & definition & end_of_capitalised_word
            .Execute
            If Not .Found Then
                quoted_definitions(definition) = False
            End If
        End With
            
    Next
    
End Sub

Sub highlight_unused_definitions()
Dim definition As Variant
Dim search_range As Word.Range
Dim search_text As String
Dim replace_text As String

    replace_text = "[\1\2]"
    For Each definition In quoted_definitions.keys
        If Not quoted_definitions(definition) Then
            Set search_range = search_doc.StoryRanges(wdMainTextStory)
            search_range.Select
            search_text = "(" & open_smart_quote & ")" & "(" & definition & ")" ' & end_of_capitalised_word
            With search_range.Find
                .ClearFormatting
                .Replacement.ClearFormatting
                .MatchWildcards = True
                .Wrap = wdFindStop
                .Text = search_text
                .Replacement.Text = replace_text
                .Replacement.Highlight = True
                .Execute Replace:=wdReplaceOne
                Set search_range = Nothing
                ' if preferred you could add here the code to add a comment rqather than highlight the text
            End With
        End If
    Next
End Sub

Sub highlight_capitalised_phrases_with_no_definition()

Dim search_range As Word.Range

    Set search_range = search_doc.StoryRanges(wdMainTextStory)

    With search_range.Find
        .ClearFormatting
        .Replacement.ClearFormatting
        .MatchWildcards = True
        .Wrap = wdFindStop
        .Text = capitalised_word & end_of_capitalised_word
        .Execute
        Do Until search_range.Text = vbNullString
            update_search_range_to_whole_capitalised_phrase search_range
            update_search_range_to_capitalised_phrase_text search_range
            do_actions_for_capitalised_phrase search_range
            search_range.Move unit:=wdWord
            .Execute
        Loop
    End With

End Sub

Sub do_actions_for_capitalised_phrase(this_range As Word.Range)

    If Not quoted_definitions.Exists(this_range.Text) Then
        search_doc.Comments.Add Range:=this_range.Duplicate, Text:="Capitalised phrase with no corresponding definition"
        ' alternatively, if a highlihght if preferred over a comment
        ' this_range.HighlightColorIndex=wdRed
    End If
             
End Sub
Reply With Quote