VBA Word Expand Range with one line - excel

First of all this is the first time I am creating a macro using VBA code. With some bits and pieces i found on the internet I tried to create the following. I am not a developer at all, I just have some basic knowledge from school. So my apologies if this is poor coding.
I am creating a macro in word which highlights text from a paragraph heading until the next heading with the same style. This is done based on a list of headings I import from Excel. You can find the code I have created below. The result with few input is perfect, so that's a good thing! The execution is very slow though (3 to 4h), which is probably related to the many selects I use. (I read only this is very often the cause of slow macros)
I tried to expand my Range with one line at the time using " Range.Expand Unit:=wdLine " but it's giving me errors every time. Therefore I use the moveDown selection method now which is doing the trick. Does anyone know a way I could use ranges here to speed up the process?
Many thanks in advance.
Sub Highlight_WordN()
Dim par As Paragraph
Dim par2 As Paragraph
Dim doc As Document
Dim oRng As Range
Dim Sty As Style
Dim intCurrentLine As Integer
Dim strFindArray() As String
Dim strIn As String
Dim strWorkBookName As String
Dim strNumberCells As String
Dim MessageFound As String
Dim MessageNotFound As String
Dim Flag As Boolean
Dim IsHeading As Boolean
Dim IsNothing As Boolean
'*****Set parameters for performance*****
Word.Application.ScreenUpdating = False
Word.Application.Options.CheckGrammarAsYouType = False
Word.Application.Options.CheckGrammarWithSpelling = False
Word.Application.Options.CheckSpellingAsYouType = False
Word.Application.Options.AnimateScreenMovements = False
Word.Application.Options.BackgroundSave = False
Word.Application.Options.CheckHangulEndings = False
Word.Application.Options.DisableFeaturesbyDefault = True
'*****Load data from excel*****
'List of headers to delete
Dim xlApp As Object
Dim xlBook As Object
strWorkBookName = "C:\Users\driesenn\OneDrive\OMAR\UPDATE\ToDelete.xlsx"
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If Err Then
Set xlApp = CreateObject("Excel.Application")
End If
On Error GoTo 0
Set xlBook = xlApp.Workbooks.Open(FileName:=strWorkBookName)
xlApp.Visible = False
ArrayLen = 0
ArrayLen = xlApp.ActiveSheet.Range("B1")
strNumberCells = "A1:A" & ArrayLen
strArray = xlApp.Transpose(xlApp.ActiveSheet.Range(strNumberCells))
ArrayLen = 0
ArrayLen = UBound(strArray) - LBound(strArray) + 1
Set xlBook = Nothing
xlApp.Quit
Set xlApp = Nothing
'*****Start evaluation process for headers*****
ArrayLen = UBound(strArray) - LBound(strArray) + 1
'Loop over all headers in the array
For i = 1 To ArrayLen
strFind = strArray(i)
'Evaluate every paragraph heading
For Each par In ActiveDocument.Paragraphs
If par.Style Like "Heading*" Then
Set Sty = par.Style
'Search for the header number in the heading
If InStr(par.Range.Text, strFind) = 1 Then
Set oRng = par.Range
oRng.Select
intCurrentLine = oRng.Information(wdFirstCharacterLineNumber)
Set oRng = Selection.Next(Unit:=wdLine, Count:=1)
'If the next line is not a header --> go on
IsHeading = False
If oRng.Style Like "Heading*" Then
IsHeading = True
End If
'Keep looping until the next heading of this type is found
Do While oRng.Style > Sty Or IsHeading = False
Selection.MoveDown Unit:=wdLine, Count:=1, Extend:=wdExtend
Set oRng = Selection.Next(Unit:=wdLine, Count:=1)
If oRng Is Nothing Then
Exit Do
End If
'If the next line is not a header --> go on
IsHeading = False
If oRng.Style Like "Heading*" Then
IsHeading = True
End If
Loop
Selection.Start = par.Range.Start
'If we are not at the end of the document selection ends with last line of current range.
If oRng Is Nothing Then
Else
Selection.End = oRng.Start
End If
'Set highlight
Selection.Range.HighlightColorIndex = wdYellow
End If
End If
Next
Next
End Sub

Firstly, it will assist you to become familiar with using help. Place your cursor in the keyword that you need help with and press F1. Had you done so for the Expand method you would have landed here. You will find the valid parameters for Unit are listed.
Secondly, paragraph styles are applied to paragraphs not lines. So you need to check the style of each paragraph and expand the range by one paragraph at a time. This will enable you to avoid selecting anything.

The following code shows a much easier way of highlighting the ranges associated with different heading levels, using Word's built-in '\HeadingLevel' bookmark:
Sub Demo()
Dim h As Long, c As Long, Rng As Range
For h = 1 To 9
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Style = "Heading " & h
.Replacement.Text = ""
.Format = True
.Forward = True
.Execute
End With
Do While .Find.Found
Set Rng = .Paragraphs(1).Range
Set Rng = Rng.GoTo(What:=wdGoToBookmark, Name:="\HeadingLevel")
Select Case h
Case 1 To 4: c = h + 1
Case 5: c = h + 2
Case 6 To 8: c = h + 4
Case 9: c = h + 5
Case Else: c = 0
End Select
Rng.HighlightColorIndex = c
.Collapse wdCollapseEnd
If .Information(wdWithInTable) = True Then
If .End = .Cells(1).Range.End - 1 Then
.End = .Cells(1).Range.End
.Collapse wdCollapseEnd
If .Information(wdAtEndOfRowMarker) = True Then .End = .End + 1
End If
End If
If .End = ActiveDocument.Range.End Then Exit Do
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Next
End Sub
Of course, as the above code loops through all 9 heading levels, what ends up with a given highlight depends on how many other lower-level headings (higher numbers) are nested within a given higher-level heading (lower numbers).

Related

Excel to Word VBA. Create Hover Texts for 25k Definitions

What is the BEST option to create Hover Texts for 25k Definitions?
(Excel to Word using VBA)
Screen Tips?
Tool Tips?
Foot Notes?
Glossary?
Book Marks?
Other Options?
Over 25K Definitions in Table
Based on feedback and countless HOURS, Im having a tough time figuring out the best option for a Text Hover Effect.
Ive tried Bookmarks and Screen Tips and ran into many issues.
Ive also attempted to tweak the below VBA code to work with Hyperlinks to no avail.
3 STEPS
Select the Term from Column:A
Find the Term in Word Document
ADD Definition From Column:B as a HOVER effect in Word
| Column A | Column B |
| ----------- | ------------------------ |
| Example A | Definition Example.... |
| Example B | Definition Example.... |
Column: A1:A25000 = Term
Column: B1:B25000 = Definition
*The below code works great for finding and highlighting the Terms, But I haven't figured out the Hover Effect.
Favor 2023
`'Version #1: Only loops through Word Document Content for text to Find and Replace.
'Leverage & Lean "Less Clicks, More Results"
Sub FindReplaceAcrossMultipleWordDocumentsFreeMacro()
' Means variable is in use
Dim FindReplaceCounter As Integer '
Dim FolderPath As String '
Dim LastRow As Integer '
Dim LastRowPath As Integer '
Dim MyRange As Object '
Dim oFile As Object '
Dim oFolder As Object '
Dim oFSO As Object '
Dim WordApp As New Word.Application '
Dim WordCounter As Integer '
Dim WordDocument As Object '
On Error GoTo LeverageLean
Set WordApp = New Word.Application 'Forces a New Word Application each and every time. (Prevents Error 462)
If Cells(2, 3).Value <> "" Then 'If a path to Word Documents exist
WordCounter = 2
LastRowPath = Cells(Rows.Count, 3).End(xlUp).Row 'Identify Last Row in Column C
Do Until WordCounter > LastRowPath 'Loop through any Word Documents in Column C
Set WordDocument = WordApp.Documents.Open(Cells(WordCounter, 3).Value)
WordApp.Visible = True
FindReplaceCounter = 2
LastRow = Cells(Rows.Count, 1).End(xlUp).Row 'Identify Last Row in Column A
Do Until FindReplaceCounter > LastRow 'Complete the Find and Replace for all values in Column A & B
Set MyRange = WordApp.ActiveDocument.Content
With MyRange.Find
.Format = True
.MatchWholeWord = True
'.MatchWildcards = True 'Find and Replace Uppercase & Lowercase Text
.Wrap = wdFindContinue
.Forward = True
.Text = Cells(FindReplaceCounter, 1).Value
'.Replacement.Highlight = True 'Highlight the Replacement Text Found
.Replacement.Text = Cells(FindReplaceCounter, 2).Value
.Execute Replace:=wdReplaceAll
End With
FindReplaceCounter = FindReplaceCounter + 1
Loop
WordApp.ActiveDocument.Save
WordApp.ActiveDocument.Close 'Close Active Word Document
WordCounter = WordCounter + 1
Loop
ElseIf Cells(2, 3).Value = "" Then 'If NO paths to Word Documents exist
FolderPath = Left(ActiveWorkbook.FullName, Len(ActiveWorkbook.FullName) - Len(ActiveWorkbook.Name)) 'Active Workbook File Path
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = oFSO.GetFolder(FolderPath)
For Each oFile In oFolder.Files 'Loop through every File in Active Workbook's folder path
If InStr(1, oFile.Type, "Microsoft Word") <> 0 And InStr(1, oFile.Name, "~") = 0 Then 'If the File Type contains the phrase Microsoft Word and is NOT Lock File
Set WordDocument = WordApp.Documents.Open(FolderPath & oFile.Name)
WordApp.Visible = True
FindReplaceCounter = 2
LastRow = Cells(Rows.Count, 1).End(xlUp).Row 'Identify Last Row in Column A
Do Until FindReplaceCounter > LastRow 'Complete the Find and Replace for all values in Column A & B
Set MyRange = WordApp.ActiveDocument.Content
With MyRange.Find
.Format = True
.MatchWholeWord = True
.Wrap = wdFindContinue
.Forward = True
.Text = Cells(FindReplaceCounter, 1).Value
'.Replacement.Highlight = True 'Highlight the Replacement Text Found
.Replacement.Text = Cells(FindReplaceCounter, 2).Value
.Execute Replace:=wdReplaceAll
End With
FindReplaceCounter = FindReplaceCounter + 1
Loop
WordApp.ActiveDocument.Save
WordApp.ActiveDocument.Close 'Close Active Word Document
End If
Next oFile
End If
WordApp.Quit
MsgBox "The Find and Replace has been completed. Stay Awesome!"
Set oFSO = Nothing
Set oFolder = Nothing
Set oFile = Nothing
Set WordApp = Nothing
Set WordDocument = Nothing
Exit Sub
LeverageLean:
MsgBox (Err.Number & " - " & Err.Description & vbNewLine & vbNewLine & "Don't hesitate to email me: brentschneider#leveragelean.com")
End Sub
'Stay Awesome`

Find And Replace Text, retain Formatting

I have an excel file that I need to do a find and replace and the cells have formatting already. I need to retain the formatting. When I do an ordinary find and replace in excel, this removes the formatting. I need help to retain the formatting. I searched online and found the below link but this code is not working for me.
When I try the below code, this line is red in the code.
Call CharactersReplace(xRg, "<span style="background-color: #ffff00;">KK</span>", "<span style="background-color: #ffff00;">Kutools</span>", True)
I need help to correct this code and get this to work. Or if there is an easier way to do this, please let me know.
https://www.extendoffice.com/documents/excel/3760-excel-find-and-replace-preserve-formatting.html
Sub CharactersReplace(Rng As Range, FindText As String, ReplaceText As String, Optional MatchCase As Boolean = False)
'UpdatebyExtendoffice20160711
Dim I As Long
Dim xLenFind As Long
Dim xLenRep As Long
Dim K As Long
Dim xValue As String
Dim M As Long
Dim xCell As Range
xLenFind = Len(FindText)
xLenRep = Len(ReplaceText)
If Not MatchCase Then M = 1
For Each xCell In Rng
If VarType(xCell) = vbString Then
xValue = xCell.Value
K = 0
For I = 1 To Len(xValue)
If StrComp(Mid$(xValue, I, xLenFind), FindText, M) = 0 Then
xCell.Characters(I + K, xLenFind).Insert ReplaceText
K = K + xLenRep - xLenFind
End If
Next
End If
Next
End Sub
Sub Test_CharactersReplace()
Dim xRg As Range
Dim xTxt As String
Dim xCell As Range
On Error Resume Next
If ActiveWindow.RangeSelection.Count > 1 Then
xTxt = ActiveWindow.RangeSelection.AddressLocal
Else
xTxt = ActiveSheet.UsedRange.AddressLocal
End If
Set xRg = Application.InputBox("Select a range:", "Kutools for Excel", xTxt, , , , , 8)
If xRg Is Nothing Then Exit Sub
Call CharactersReplace(xRg, "<span style="background-color: #ffff00;">KK</span>", "<span style="background-color: #ffff00;">Kutools</span>", True)
End Sub
I appreciate what I learned from the comment by #Marc but after trying to edit the xml, I found it was just too complicated. Any little mistake I made rendered the xml file unopenable by Excel.
So my solution was to copy the sheet into Word (it comes in as a Word table), using Word's Advanced Find and Replace features, and then pasting the table back into the Excel sheet. It worked for me.
Because I had lot of sheets I wanted to do this with, I made this VBA routine. After copying my data (in the first 2 columns) into Word, it removes all superscripted characters, plus does some formatting I needed. Not pretty but it worked to do 72 sheets for me, saving a lot of tedious work.
Sub ExcelSheetsEditedViaWord()
' note: must add a reference to the Word-library (Microsoft Word 16.0 Object Lilbrary)
Dim wrdApp As Word.Application
Dim wrdDoc As Word.Document
Dim s As String, i As Integer, sh As Worksheet, r As Range
Application.DisplayStatusBar = True
Application.StatusBar = "Opening Word ..."
Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
Set wrdDoc = wrdApp.Documents.Add
With ActiveDocument.PageSetup
.PageWidth = InchesToPoints(11)
.PageHeight = InchesToPoints(22)
End With
wrdApp.ActiveWindow.ActivePane.View.Zoom.Percentage = 40
i = 0
For Each sh In ThisWorkbook.Worksheets
Set r = sh.Range("A1:B1")
Set r = sh.Range(r, r.End(xlDown))
r.Copy
'wait to avoid error that sometimes stops code.
Application.Wait (Now + TimeValue("0:00:01"))
wrdDoc.Range.PasteExcelTable False, False, False
sh.Activate
sh.Range("A1").Select
With wrdApp.Selection
.Find.ClearFormatting
With .Find.Font
.Superscript = True
.Subscript = False
End With
.Find.Replacement.ClearFormatting
With .Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
End With
.Find.Execute Replace:=wdReplaceAll
.WholeStory
.Cut
'wait some second to try to avoid error that stops code. However,
'even when code stops, hitting debug allows it to continue
Application.Wait (Now + TimeValue("0:00:06"))
sh.Paste
With sh.Columns("A:B")
.VerticalAlignment = xlTop
.WrapText = True
.Font.Name = "Times New Roman"
.Font.Size = 16
End With
i = i + 1
End With
Application.StatusBar = i & " sheets done"
Next sh
wrdApp.Quit False ' close the Word application
Set wrdDoc = Nothing
Set wrdApp = Nothing
MsgBox i & " sheets of the workbook processed"
End Sub
I have some Application.Wait() statements where the code would fail occasionally -- something I've seen a lot with code that copy/pastes between Excel and Word. But when it fails, clicking debug and continuing works every time. As I said, not pretty but gets the job done.

VBA convert embedded excel sheet to word table in word file

I need to convert the embedded excel sheet object to word table in word file, I am currently using is to open the embedded excel sheet object , select the content and paste to word. Could there be a better way to simplify this action?
I try to create a mirco but .OLEformat keep error and said this member cannot be accessed on a horizontal line.
Sub ConvertXLObjs()
Application.WindowState = wdWindowStateMinimize
Dim i As Long, j As Long, k As Long, Rng As Range, bDel As Boolean
Dim objOLE As Word.OLEFormat, objXL As Object
With ActiveDocument
For i = .InlineShapes.Count To 1 Step -1
With .InlineShapes(i)
If Not .OLEFormat Is Nothing Then
If Split(.OLEFormat.ClassType, ".")(0) = "Excel" Then
Set Rng = .Range
Set objOLE = .OLEFormat
objOLE.Activate
Set objXL = objOLE.Object
With objXL.ActiveSheet
.Range("$A$1:" & _
.Cells.SpecialCells(11).Address).Copy ' 11 = xlCellTypeLastCell
End With
objXL.Application.Undo
.Delete
With Rng
.Characters.First.PasteAndFormat wdTableInsertAsRows
.MoveEnd wdParagraph, 2
With .Tables(1)
.AllowAutoFit = False
.BottomPadding = 0
.LeftPadding = 0
.RightPadding = 0
.TopPadding = 0
.Rows.AllowBreakAcrossPages = False
.Rows.HeightRule = wdRowHeightExactly
If .Uniform = True Then
For j = .Columns.Count To 1 Step -1
bDel = True
For k = 1 To .Columns(j).Cells.Count
If Len(.Columns(j).Cells(k).Range.Text) > 2 Then
bDel = False
Exit For
End If
Next
If bDel = True Then
.Columns(j).Delete
Else
Exit For
End If
Next
End If
End With
End With
End If
End If
End With
Next
End With
Set objXL = Nothing: Set objXL = Nothing: Set Rng = Nothing
Application.WindowState = wdWindowStateNormal
MsgBox "Finished processing!"
End Sub
the code is refer from https://social.msdn.microsoft.com/Forums/office/en-US/5955da06-725d-45f2-aa1b-5eb37c0646c6/how-to-convert-all-embeded-excel-sheets-in-word-into-words-tables?forum=worddev
Example:

How to return focus to Word document from where the macro opened Excel file

Private Sub CommandButton1_Click()
Dim oRng As Word.Range
Dim arrExcelValues()
Dim i As Long
Dim x As Long
Set objExcel = CreateObject("Excel.Application")
Set objWorkbook = objExcel.Workbooks.Open("C:\Risk Words.xlsx")
objExcel.Visible = False
i = 1
x = 0
Do Until objExcel.Cells(i, 1).Value = ""
ReDim Preserve arrExcelValues(x)
arrExcelValues(x) = objExcel.Cells(i, 1).Value
i = i + 1
x = x + 1
Loop
objExcel.Quit
For i = 0 To UBound(arrExcelValues)
Set oRng = ActiveDocument.Range
Options.DefaultHighlightColorIndex = wdYellow
With oRng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = arrExcelValues(i)
.MatchWholeWord = True
.Replacement.Highlight = True
.Execute Replace:=wdReplaceAll
End With
Next
End Sub
Wrote this code to pick words from the Excel file and check it in the Word file to see if they are present and highlight them. However, it does not seem to work from Set oRng = ActiveDocument.Range. Although, if I put a MsgBox before that, it does show the values picked up from the Excel and store in the array.
If you're calling the macro from the Word document, then setting the oRng before you open Excel file might help. Or you could put Word.Application.Activate before trying to write to Word

Copy formatted text from excel to word

I have an excel sheet with two columns of strings. I track the changes of these two columns using ms-word and copy the result back to a third column. Then I copy the third column to a new word document.
The formating in Excel in Cell C3 is what I would like to transfer to word.
This is what I get at the moment. Notice the complete strike-through.
Why does it work twice but not in the third case?
I guess the root of the problem is that I remove the CR/Linefeed in the word to excel step and destroy the boundary of the strike-through-format. My goal is to get each string in one word-paragraph. If I don't remove the CR/Linefeed i get four paragraphs.
Background: In the final application the strings are going to be paragraphs of text.
Sourcecode of the excel-vba-macro (Excel 2010):
Technical remark: You may need to activate the ms-word-objects in excel-vba. (Microsoft Word 14.0 Object Library )
The macro assumes, that there a strings in the Range(A1:B3):
for example
a string a string, too
a string a new string
a string there is no try
The results will be put in the Range(C1:C3).
Option Explicit
Dim numberOfBlocks As Long
Sub main()
Dim i As Long
Dim tSht As Worksheet
Dim wordapp As Word.Application
Dim wdoc As Word.Document
Set tSht = ThisWorkbook.ActiveSheet
numberOfBlocks = 3
Application.ScreenUpdating = False
Set wordapp = CreateObject("Word.Application")
For i = 1 To numberOfBlocks
Call trackChanges(i, wordapp, tSht)
Next i
Set wdoc = wordapp.Documents.Add
Call copyChanges(tSht, wdoc)
End Sub
Sub trackChanges(i As Long, wordapp As Word.Application, tSht As Worksheet)
Dim diffDoc As Word.Document
Dim textString() As Variant
Dim j As Long
ReDim doc(2)
ReDim textString(2)
Set textString(1) = tSht.Range("A" & i)
Set textString(2) = tSht.Range("B" & i)
For j = 1 To 2
With wordapp
Set doc(j) = .Documents.Add
textString(j).Copy
doc(j).Paragraphs(1).Range.PasteSpecial
End With
Next j
wordapp.CompareDocuments OriginalDocument:=doc(1), RevisedDocument:=doc(2), _
Destination:=wdCompareDestinationNew, Granularity:=wdGranularityCharLevel
For j = 1 To 2
doc(j).Close SaveChanges:=False
Next j
Set diffDoc = wordapp.ActiveDocument
wordapp.Visible = True
'if the answer has two paragraphs, get both in one paragraph
With diffDoc.Content.Find
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
.Text = vbCrLf
.Replacement.Text = " "
.Execute Replace:=wdReplaceAll
End With
diffDoc.Range.Copy
tSht.Range("C" & i).Select
tSht.PasteSpecial Format:="HTML"
With tSht.Range("C" & i)
.WrapText = True
.Font.Name = textString(2).Font.Name
.Font.Bold = textString(2).Font.Bold
.Font.Size = textString(2).Font.Size
.Rows.AutoFit
.Interior.Color = textString(2).Interior.Color
End With
diffDoc.Close SaveChanges:=False
Application.CutCopyMode = False
Set diffDoc = Nothing
End Sub
Sub copyChanges(tSht As Worksheet, wdoc As Word.Document)
tSht.Range("C1:C" & numberOfBlocks).Copy
wdoc.Range(wdoc.Range.End - 1, wdoc.Range.End).PasteSpecial Placement:=wdInLine, DataType:=wdPasteHTML
wdoc.Tables(1).ConvertToText Separator:=wdSeparateByParagraphs
End Sub

Resources