I am trying to create a Word macro VBA to do the following:
for the active Word document
find the name “Bob” and count how many times “this is new” is associated to Bob (recursion search and count)
For example. Bob = 2, Matthew = 1, Mark = 0
Report – JP
PQR – Bob, Mark
· Some text
Report – SH
JKL – Bob, Mark
· Some text
GHI – Bob
· This is new.
· More text
Report – JM
MNO – Bob, Mark
· Some text
DEF – Bob
· This is new.
· More text
ABC – Matthew
· This is new.
· More text
Report – BB
PQR – Bob, Mark
· Some text
I believe that my attempt using this code is not correct. Any help?
sResponse = "is new"
iCount = 0
Application.ScreenUpdating = False
With Selection
.HomeKey Unit:=wdStory
With .Find
.ClearFormatting
.Text = sResponse
' Loop until Word can no longer
' find the search string and
' count each instance
Do While .Execute
iCount = iCount + 1
Selection.MoveRight
Loop
End With
MsgBox sResponse & " appears " & iCount & " times
For example:
Sub Demo()
Application.ScreenUpdating = False
Dim StrNm As String, StrOut As String, i As Long
StrOut = "Bob = 0, " & _
"Matthew = 0, " & _
"Mark = 0, "
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "<[! ]# · This is new"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
End With
Do While .Find.Execute
If .Text = "" Then Exit Do
StrNm = Split(.Text, " ")(0)
If InStr(StrOut, StrNm) > 0 Then
i = Split(Split(StrOut, StrNm & " = ")(1), ", ")(0)
StrOut = Replace(StrOut, StrNm & " = " & i, StrNm & " = " & i + 1)
Else
StrOut = StrOut & StrNm & " = " & 1 & ", "
End If
.Collapse wdCollapseEnd
Loop
End With
Application.ScreenUpdating = True
MsgBox "Frequency Report:" & StrOut
End Sub
If you've missed any names with 'This is new', the code above will simply add them to the pre-defined StrOut list.
A part of your stated original problem was that you wanted to list ALL of the names, including names that NEVER show up as lines with the phrase "This is new". So the code must build a Dictionary of names and keep track of each name and its count as all the lines are scanned. (See this site for good information on dictionaries.)
There are a couple of "gotchas" in the ultimate solution, including allowing for names with accented characters (e.g. José) and names with spaces (e.g. "Bob Smith"). So I created a special "trim" function to scan each name and make sure the string is really just the name.
Assumptions:
Lines that DO NOT begin with "Report" are the lines that have names
The words separated by commas after the dash character are the names
The list of names ends when you find the special "separator" character
Here is the example code:
Option Explicit
Sub CountPhrase()
'--- define the dash and separator characters/strings - may be special codes
Dim dash As String
Dim separator As String
Dim phrase As String
dash = "–" 'this is not a keyboard dash
separator = "·" 'this is not a keyboard period
phrase = "This is new"
Dim nameCount As Scripting.Dictionary
Set nameCount = New Scripting.Dictionary
Dim i As Long
For i = 1 To ThisDocument.Sentences.Count
'--- locate the beginning of the names lines (that DO NOT have start with "Report")
If Not (ThisDocument.Sentences(i) Like "Report*") Then
'--- pick out the names for this report
Dim dashPosition As Long
Dim separatorPosition As Long
dashPosition = InStr(1, ThisDocument.Sentences(i), dash, vbTextCompare)
separatorPosition = InStr(1, ThisDocument.Sentences(i), separator, vbTextCompare)
Dim names() As String
names = Split(Mid$(ThisDocument.Sentences(i), _
dashPosition + 1, _
separatorPosition - dashPosition), ",")
'--- now check if the phrase exists in this sentence or not
Dim phrasePosition As Long
phrasePosition = InStr(1, ThisDocument.Sentences(i), phrase, vbTextCompare)
'--- add names to the dictionary if they don't exist, and increment
' the name count if the phrase exists in this sentence
Dim name As Variant
For Each name In names
Dim thisName As String
thisName = SpecialTrim$(name)
If Len(thisName) > 0 Then
If nameCount.Exists(thisName) Then
If phrasePosition > 0 Then
nameCount(thisName) = nameCount(thisName) + 1
End If
Else
If phrasePosition > 0 Then
nameCount.Add thisName, 1
Else
nameCount.Add thisName, 0
End If
End If
End If
Next name
End If
Next i
'--- show your work
Dim popUpMsg As String
popUpMsg = "Frequency Report:"
For Each name In nameCount.Keys
popUpMsg = popUpMsg & vbCrLf & name & _
": count = " & nameCount(name)
Next name
MsgBox popUpMsg, vbInformation + vbOKOnly
End Sub
Function SpecialTrim(ByVal inString As String) As String
'--- this function can be tricky, because you have to allow
' for characters with accents and you must allow for names
' with spaces (e.g., "Bob Smith")
'--- trim from the left until the first allowable letter
Dim keepString As String
Dim thisLetter As String
Dim i As Long
For i = 1 To Len(inString)
thisLetter = Mid$(inString, i, 1)
If LetterIsAllowed(thisLetter) Then
Exit For
End If
Next i
'-- special case: if ALL of the letters are not allowed, return
' an empty string
If i = Len(inString) Then
SpecialTrim = vbNullString
Exit Function
End If
'--- now transfer allowable characters to the keeper
' we're done when we reach the first unallowable letter (or the end)
For i = i To Len(inString)
thisLetter = Mid$(inString, i, 1)
If LetterIsAllowed(thisLetter) Then
keepString = keepString & thisLetter
Else
Exit For
End If
Next i
SpecialTrim = Trim$(keepString)
End Function
Function LetterIsAllowed(ByVal inString As String) As Boolean
'--- inString is expected to be a single character
' NOTE: a space " " is allowed in the middle, so the caller must
' Trim the returned string
Const LETTERS = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" & _
"àáâãäåçèéêëìíîïðñòóôõöùúûüýÿŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝ"
Dim i As Long
For i = 1 To Len(LETTERS)
If inString = Mid$(LETTERS, i, 1) Then
LetterIsAllowed = True
Exit Function
End If
Next i
LetterIsAllowed = False
End Function
Related
I have written a procedure to find passive constructions, e.g. 'was solved', 'been written', i.e. passives ending in 'ed' or 'en', but not things like 'was fruitful'. A comment is inserted for each find.
I'm almost there - but cannot fix a couple of anomalies:
It works for 'was solved.' , 'was solved .' and 'was solved ', (NB spaces in two of these) but not in 'was solved today', i.e. where there are more words after the final verb. This last error is the one I wish to fix.
It also finds the passives in 'is being completed', i.e. two auxiliary verbs together, whether spaces follow the final verb or not. This is an added bonus, apart from the fact that the find is indicated twice.
I suspect this is to do with my Is_Alpha function, which strips punctuation from the end of the main verb.
Thanks folks, any help appreciated.
Sub Passives3()
Dim P_Flag As Boolean
Dim P_Cmt As Comment
Dim P_Rng As Range
Dim P_Rng2 As String
Dim P_New As String
Dim P_Fnd As Boolean
Dim Cmt As Comment
Dim P_Range As Range
Dim P_Ctr As Long
Dim Com_plete As Integer
Dim P_Word(7) As String
P_Word(0) = "am "
P_Word(1) = "are "
P_Word(2) = "be "
P_Word(3) = "been "
P_Word(4) = "being "
P_Word(5) = "is "
P_Word(6) = "was "
P_Word(7) = "were "
For P_Ctr = LBound(P_Word) To UBound(P_Word)
Set P_Rng = ActiveDocument.Range
With P_Rng.Find
.ClearFormatting
.text = P_Word(P_Ctr)
Debug.Print .text
.MatchCase = False
.MatchWholeWord = True
While .Execute
If P_Rng.Find.Found Then
Dim P_test As Range
Set P_test = P_Rng.Duplicate
With P_test
.MoveEnd wdWord, 2
.Select
P_New = P_test
Call Is_Alpha(P_New, P_Flag)
If P_Flag = False Then
P_New = Left(P_New, Len(P_New) - 1)
End If
End With
If (Right(Trim(P_New), 2)) = "ed" _
Or (Right(Trim(P_New), 2)) = "en" Then
Set P_Cmt = P_Rng.Comments.Add(Range:=P_Rng, text:="Passive? " & P_New)
P_Cmt.Author = "Passives"
P_Cmt.Initial = "PSV "
P_Cmt.Range.Font.ColorIndex = wdGreen
End If
End If
Wend
End With
Next
End Sub
Function Is_Alpha(P_New As String, P_Flag As Boolean) As Boolean
If Asc(Right(P_New, 1)) > 64 And Asc(Right(P_New, 1)) < 90 Or _
Asc(Right(P_New, 1)) > 96 And Asc(Right(P_New, 1)) < 123 Then
P_Flag = True
Else
P_Flag = False
End If
End Function
How about:
Sub Passives()
Dim i As Long, j As Long, Cmt As Comment, P_Words, X_Words
P_Words = Array("am ", "are ", "be ", "been ", "being ", "is ", "was ", "were ")
X_Words = Array("am ", "are ", "being ", "is ", "was ", "were ", "has ", "have ")
For i = LBound(P_Words) To UBound(P_Words)
With ActiveDocument.Range
With .Find
.ClearFormatting
.Text = "<" & P_Words(i) & "[! ]#e[dn]>"
.MatchWildcards = True
End With
Do While .Find.Execute
For j = LBound(X_Words) To UBound(X_Words)
If .Words.First.Previous.Words.First.Text = X_Words(j) Then
.Start = .Words.First.Previous.Words.First.Start
End If
Next
Set Cmt = .Comments.Add(Range:=.Duplicate, Text:="Passive?")
With Cmt
.Author = "Passives"
.Initial = "PSV "
.Range.Font.ColorIndex = wdGreen
End With
.Collapse wdCollapseEnd
Loop
End With
Next
End Sub
Book endnotes often forgo superscript numbers for page numbers. E.g., instead of
Abe Lincoln was assassinated with a pistol.^33
:
33. A single-shot derringer pistol.
books by several authors write
Abe Lincoln was assassinated with a pistol.
:
Page 297. Abe Lincoln was shot single-shot derringer pistol.
Word doesn't have this feature, so I believe it would have to be a Macro. I came up with simple code below that loops through all of the endnotes and adds
"Page ???. "
before each endnote, but what does "???" need to be to correctly insert the page number in my manuscript that the citation's located on?
Sub RedefineExistingEndNotes()
Dim fn As Endnote
For Each fn In ActiveDocument.Endnotes
fn.Range.Paragraphs(1).Range.Font.Reset
fn.Range.Paragraphs(1).Range.Characters(1).InsertBefore "Page" & "???" & " - "
Next fn
End Sub
Try the below VBA code:
Sub InsertPageNumberForEndnotes()
Dim endNoteCount As Integer
Dim curPageNumber As Integer
If ActiveDocument.Endnotes.Count > 0 Then
For endNoteCount = 1 To ActiveDocument.Endnotes.Count
Selection.GoTo What:=wdGoToEndnote, Which:=wdGoToAbsolute, Count:=endNoteCount
curPageNumber = Selection.Information(wdActiveEndPageNumber)
ActiveDocument.Endnotes(endNoteCount).Range.Select
ActiveDocument.Application.Selection.Collapse (WdCollapseDirection.wdCollapseStart)
ActiveDocument.Application.Selection.Paragraphs(1).Range.Characters(1).InsertBefore "Page " & CStr(curPageNumber) & " - "
Next
End If
End Sub
An alternative might be to use PAGEREF fields and hide the endnote references, e.g.
Sub modifyEndNotes()
Const bookmarkText As String = "endnote"
Dim en As Word.Endnote
Dim rng As Word.Range
For Each en In ActiveDocument.Endnotes
en.Reference.Bookmarks.Add bookmarkText & en.Index
en.Reference.Font.Hidden = True
Set rng = en.Range
rng.Paragraphs(1).Range.Font.Hidden = True
rng.Collapse WdCollapseDirection.wdCollapseStart
rng.Text = "Page . "
rng.SetRange rng.End - 2, rng.End - 2
rng.Fields.Add rng, WdFieldType.wdFieldEmpty, "PAGEREF " & bookmarkText & en.Index & " \h", False
'if necessary...
'rng.Fields.Update
en.Range.Font.Hidden = False
Next
Set rng = Nothing
End Sub
For a second run, you'd need to remove and re-insert the text and fields you had added.
Unfortunately, a further look suggests that it would be difficult, if not impossible, to hide the endnote references (in the endnotes themselves) without hiding the paragraph marker at the end of the first endnote para, which means that all the endnotes will end up looking like a single messy note. So I deleted this Answer.
However, the OP thought the approach could be modified in a useful way so I have undeleted. I can't re-research it right away but some possibilities might be to replace every endnote mark by a bullet (as suggested by the OP) or perhaps even something as simple as a space or a "-".
For example, something like this (which also hides the references using a different technique)...
Sub modifyEndNotes2()
' this version also formats the endnotes under page headings
Const bookmarkText As String = "endnote"
Dim en As Word.Endnote
Dim f As Word.Field
Dim i As Integer
Dim rng As Word.Range
Dim strSavedPage As String
strSavedPage = ""
For Each en In ActiveDocument.Endnotes
en.Reference.Bookmarks.Add bookmarkText & en.Index
Set rng = en.Range
rng.Collapse WdCollapseDirection.wdCollapseStart
If CStr(en.Reference.Information(wdActiveEndPageNumber)) <> strSavedPage Then
strSavedPage = CStr(en.Reference.Information(wdActiveEndPageNumber))
rng.Text = "Page :-" & vbCr & " - "
rng.SetRange rng.End - 6, rng.End - 6
rng.Fields.Add rng, WdFieldType.wdFieldEmpty, "PAGEREF " & bookmarkText & en.Index & " \h", False
rng.Collapse WdCollapseDirection.wdCollapseEnd
Else
rng.Text = "- "
End If
Next
If ActiveDocument.Endnotes.Count > 1 Then
ActiveDocument.Styles(wdStyleEndnoteReference).Font.Hidden = True
Else
ActiveDocument.Styles(wdStyleEndnoteReference).Font.Hidden = False
End If
Set rng = Nothing
End Sub
In the above case, notice that there is only one link to each page, that formatting might be needed to make it obvious that it is a link, and so on.
I have VBA code that runs through a document and identifies acronyms using wildcards and places them in a separate word document. Some of my writers don't always follow the proper style guides for acronyms so I'm running four different scripts to find all the possible acronyms. It's time consuming and I end up with multiple documents. Is there a method to run multiple searches from one script and have all the results placed in the separate document. Truth in Advertising: I found this script on the 'net, but I've been playing with it to attempt to make it do some other features. Adding current script:
Sub ExtractVariousValuesACRONYMSToNewDocument()
'The macro creates a new document,
'finds all words consisting of 2 or more uppercase letters
'in the active document and inserts the words
'in column 1 of a 3-column table in the new document
'Each acronym is added only once
'Use column 2 for definitions
'Page number of first occurrence is added by the macro in column 3
'Minor adjustments are made to the styles used
'You may need to change the style settings and table layout to fit your needs
'=========================
Dim oDoc_Source As Document
Dim oDoc_Target As Document
Dim strListSep As String
Dim strAcronym As String
Dim oTable As Table
Dim oRange As Range
Dim n As Long
Dim strAllFound As String
Dim Title As String
Dim Msg As String
Title = "Extract Acronyms to New Document"
'Show msg - stop if user does not click Yes
Msg = "This macro finds all words consisting of 2 or more " & _
"uppercase letters and extracts the words to a table " & _
"in a new document where you can add definitions." & vbCr & vbCr & _
"Do you want to continue?"
If MsgBox(Msg, vbYesNo + vbQuestion, Title) <> vbYes Then
Exit Sub
End If
Application.ScreenUpdating = False
'Find the list separator from international settings
'May be a comma or semicolon depending on the country
strListSep = Application.International(wdListSeparator)
'Start a string to be used for storing names of acronyms found
strAllFound = "#"
Set oDoc_Source = ActiveDocument
'Create new document for acronyms
Set oDoc_Target = Documents.Add
With oDoc_Target
'Make sure document is empty
.Range = ""
'Insert info in header - change date format as you wish
.PageSetup.TopMargin = CentimetersToPoints(3)
.Sections(1).Headers(wdHeaderFooterPrimary).Range.Text = _
"Acronyms extracted from: " & oDoc_Source.FullName & vbCr & _
"Created by: " & Application.UserName & vbCr & _
"Creation date: " & Format(Date, "MMMM d, yyyy")
'Adjust the Normal style and Header style
With .Styles(wdStyleNormal)
.Font.Name = "Arial"
.Font.Size = 10
.ParagraphFormat.LeftIndent = 0
.ParagraphFormat.SpaceAfter = 6
End With
With .Styles(wdStyleHeader)
.Font.Size = 8
.ParagraphFormat.SpaceAfter = 0
End With
'Insert a table with room for acronym and definition
Set oTable = .Tables.Add(Range:=.Range, NumRows:=2, NumColumns:=3)
With oTable
'Format the table a bit
'Insert headings
.Range.Style = wdStyleNormal
.AllowAutoFit = False
.Cell(1, 1).Range.Text = "Acronym"
.Cell(1, 2).Range.Text = "Definition"
.Cell(1, 3).Range.Text = "Page"
'Set row as heading row
.Rows(1).HeadingFormat = True
.Rows(1).Range.Font.Bold = True
.PreferredWidthType = wdPreferredWidthPercent
.Columns(1).PreferredWidth = 20
.Columns(2).PreferredWidth = 70
.Columns(3).PreferredWidth = 10
End With
End With
With oDoc_Source
Set oRange = .Range
n = 1 'used to count below
With oRange.Find
'Use wildcard search to find strings consisting of 2 or more uppercase letters
'Set the search conditions
'NOTE: If you want to find acronyms with e.g. 2 or more letters,
'change 3 to 2 in the line below
.Text = "<[A-Z]{2" & strListSep & "}>"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = True
.MatchWildcards = True
'Perform the search
Do While .Execute
'Continue while found
strAcronym = oRange
'Insert in target doc
'If strAcronym is already in strAllFound, do not add again
If InStr(1, strAllFound, "#" & strAcronym & "#") = 0 Then
'Add new row in table from second acronym
If n > 1 Then oTable.Rows.Add
'Was not found before
strAllFound = strAllFound & strAcronym & "#"
'Insert in column 1 in oTable
'Compensate for heading row
With oTable
.Cell(n + 1, 1).Range.Text = strAcronym
'Insert page number in column 3
.Cell(n + 1, 3).Range.Text = oRange.Information(wdActiveEndPageNumber)
End With
n = n + 1
End If
Loop
End With
End With
'Sort the acronyms alphabetically - skip if only 1 found
If n > 2 Then
With Selection
.Sort ExcludeHeader:=True, FieldNumber:="Column 1", SortFieldType _
:=wdSortFieldAlphanumeric, SortOrder:=wdSortOrderAscending
'Go to start of document
.HomeKey (wdStory)
End With
End If
Application.ScreenUpdating = True
'If no acronyms found, show msg and close new document without saving
'Else keep open
If n = 1 Then
Msg = "No acronyms found."
oDoc_Target.Close savechanges:=wdDoNotSaveChanges
Else
Msg = "Finished extracting " & n - 1 & " acronymn(s) to a new document."
End If
MsgBox Msg, vbOKOnly, Title
'Clean up
Set oRange = Nothing
Set oDoc_Source = Nothing
Set oDoc_Target = Nothing
Set oTable = Nothing
End Sub
The best solution would be one searching pattern for all cases. Word hasn't full regular expressions, it is not always possible. Write all four patterns, maybe there is a way for join them into one super-pattern.
The second possibility is running multiple times the same algorithm in one macro, something like this:
Sub Example()
Dim patterns As String
Dim pts() As String
'list of patterns for each run delimited by a delimiter - comma in this example
patterns = "first pattern, second pattern, and so on"
pts = Split(patterns, ",") 'the second parameter is a delimiter
Dim i As Integer
For i = 0 To UBound(pts)
'do your subroutine for each searching pattern
Next i
'save document with result
End Sub
For better answer give us more details, please.
I have a Word file that contains multiple people and their details.
I need to split this file into single files for each person.
This is the code, most of it is from examples I found.
I need to split the file by the delimiter (Personal).
Each file needs to be named by their ID number situated just below the delimiter.
Sub SplitNotes (delim As String)
Dim sText As String
Dim sValues(10) As String
Dim doc As Document
Dim arrNotes
Dim strFilename As String
Dim Test As String
Dim I As Long
Dim X As Long
Dim Response As Integer
arrNotes = Split(ActiveDocument.Range, delim)
Response = MsgBox("This will split the document into " & UBound(arrNotes) + 1 & " sections.Do you wish to proceed?", 4)
If Response = 7 Then Exit Sub
For I = LBound(arrNotes) To UBound(arrNotes)
If Trim(arrNotes(I)) <> "" Then
X = X + 1
Set doc = Documents.Add
doc.Range = arrNotes(I)
'Find "EID: "
doc.Range.Find.Text = "EID: "
'Select whole line
Selection.Expand wdLine
'Assign text to variable
sText = Selection.Text
'Remove spaces
sText = Replace(sText, " ", "")
'Split string into values
sValues = Split(sText, ":")
strFilename = "Testing"
doc.SaveAs ThisDocument.Path & "\" & strFilename & Format(X, "Agent")
doc.Close True
End If
Next I
End Sub
Sub Test()
'delimiter
SplitNotes "Name:"
End Sub
The Word document is set out as follows:
Personal
Name: John Smith
EID: Alph4num3r1c (Not a set length as i know of)
Details follow on from here
My problem is getting the ID number and using it in the save as function.
I don't have a complete understanding of how the split function works.
Split function splits a string into array of strings based on a delimeter.
For eg:
Dim csvNames, arrNames
csvNames = "Tom,Dick,Harry"
arrNames = split(csvNames,",")
Now arrNames is an array containing 3 elements. You can loop through the elements like this:
Dim i
For i = 0 to UBound(arrNames)
response.write arrNames(i) & "<br />"
Next
Now applying split function to solve your problem.
Read the line you are interested in into a variable. Lets say we have,
Dim lineWithID, arrKeyValuePair
lineWithID = "EID: Alph4num3r1c"
Split it into an array using colon
arrKeyValuePair = Split(lineWithID,":")
Now, arrKeyValuePair(1) will contain your EID
If your question is still valid I have some solution regarding file name you search.
I didn't check all part of your code (so I did but I don't have your original document to make full analysis). Back to file name- you could use below simple logic to extract name from newly created doc:
'...beginning of your code here
'next part unchanged >>
For I = LBound(arrNotes) To UBound(arrNotes)
If Trim(arrNotes(I)) <> "" Then
X = X + 1
Set doc = Documents.Add
doc.Range = arrNotes(I)
'<<until this moment
'remove or comment your code here!!
'and add new part of the code to search for the name
Selection.Find.Execute "EID:"
Selection.MoveRight wdWord, 1
Selection.Expand wdWord
strFilename = Trim(Selection.Text)
'and back to your code- unchanged
doc.SaveAs ThisDocument.Path & "\" & strFilename & Format(X, "Agent")
doc.Close True
End If
Next I
'...end of sub and other ending stuff
I check it and works quite ok for me.
I am creating a project that lets the user create a task list within excel and then compares the user created tasks-text to the second header-text, (Header 2) within a pre-made word document. I am able to get the second header text and save it to an array, and then get the user task list and save that within an array. I then try and see if the task text that is within the Program (The second headers) are within the user task list using the function
If IsError(Application.Match(ProgArray(x), TaskArray, 0)) Then
'Find within word document and highlight red
End if
The problem I am getting is that this always returns with an error because for some reason, even though the built in watch screen debugger says otherwise, the text within the word document does not equal the exact same text within the excel sheet.
At first I used a comparing text software to determine that the header's text from word might have actually copied an extra line.
Picture of explanation:
But then I tried to trim, and check for whether or not the header text had vbNewLine
If Right$(StrFound, 2) = vbCrLf Or Right$(StrFound, 2) = vbNewLine Then
Also to no avail, as this if statement was never triggered.
My question is, is taking text from a word document also pulling some hidden value that I am just missing, and if so is there any way around this? Thank you and sorry for the wall of text.
Lastly here is my complete code: (Its not pretty as I am just going for functionality right now)
'Sub CheckHeader()
Dim blnFound As Boolean
Dim StrFound As String
Dim x As Integer, y As Integer, z As Integer
Dim TaskTotal As Integer
Dim ProgArray(149) As String
Dim TaskArray() As String
Dim NotInArray() As String
Dim NotInProg() As String
Dim appWd As Object
Dim TaskSheet As Worksheet
Set appWd = GetObject(, "Word.Application")
Set wdFind = appWd.Selection.Find
Set TaskSheet = Sheets("Task List")
'Get Task List from Excel
TaskTotal = TaskSheet.Cells(TaskSheet.Rows.Count, 1).End(xlUp).Row - 1
ReDim TaskArray(TaskTotal) As String
ReDim NotInProg(TaskTotal) As String
ReDim NotInArray(TaskTotal) As String
'Get User task list into an array to compare - 0 to 0 is for testing
For x = 0 To 0 'TaskTotal - 1
TaskArray(x) = TaskSheet.Cells(2 + x, 5).Value '+ " (" & TaskSheet.Cells(2 + x, 1).Value + " " _
& TaskSheet.Cells(2 + x, 3).Value + ": " & TaskSheet.Cells(2 + x, 4).Value + ")"
Next x
x = 0
y = 0
'Find all instances of Headings
With ActiveDocument.Range.Find
'.Text = "Test"
.Style = "Heading 2"
Do
blnFound = .Execute
If blnFound Then
'MsgBox .Parent.Text
StrFound = .Parent.Text
'StrFound = Right(StrFound, InStr(StrFound, ")") + 1)
StrFound = CStr(StrFound)
TaskSheet.Cells(2 + x, 120).Value = StrFound
'At first I thought it was also saving a new line but I couldn't get rid of it
If Right$(StrFound, 2) = vbCrLf Or Right$(StrFound, 2) = vbNewLine Then
z = 1
End If
ProgArray(x) = TaskSheet.Cells(2 + x, 120)
'StrFound
x = x + 1
Else
Exit Do
End If
Loop
End With
'Compare if List is in Program
For x = 0 To 149
If x < TaskTotal - 1 Then
If IsError(Application.Match(TaskArray(x), ProgArray, 0)) Then
NotInProg(y) = TaskArray(x)
y = y + 1
End If
End If
'If the header is not within the user created task list then run this case
If IsError(Application.Match(ProgArray(x), TaskArray, 0)) Then
'used for debugging, for some reason the header text is larger than the user text
MsgBox StrComp(ProgArray(x), TaskArray(x))
NotInArray(z) = ProgArray(x)
SearchName = NotInArray(z)
'Increase element
z = z + 1
'Check Program and highlight to show that what is in the program is not in the user task list
With wdFind
.Text = SearchName
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Execute
End With
If wdFind.Found Then
'MsgBox " Found it"
appWd.Selection.Range.HighlightColorIndex = wdRed
Else
MsgBox ProgArray(x) + " is not in TaskList"
End If
Else
'Otherwise it is in the program and if it was red, unhighlight the text
SearchName = TaskArray(x)
With wdFind
.Text = SearchName
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Execute
End With
If wdFind.Found Then
'MsgBox " Found it"
appWd.Selection.Range.HighlightColorIndex = wdNoHighlight
' For not in task Selection.Range.HighlightColorIndex = wdRed
' For not in prog Selection.Range.HighlightColorIndex = wdYellow
Else
MsgBox TaskArray(x) + " is not here"
End If
End If
'Lastly Check for Ordering
Next x
End Sub'
There are two problems within your code and solutions to them are as follows:
To cut new paragraph mark we need to cut it of in this way:
.Parent.SetRange .Parent.Start, .Parent.End - 1
Which you need to put just before:
StrFound = .Parent.Text
Additionally, add .Parent.MoveEnd right after x=x+1 inside your do...loop.