How to work with selection - vba

I am trying to convert perfectly working macro to hyperlink with activedoccument.range to selection.range.
code is
With Selection.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "String String1"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
strtxt = Split(.Text, " ")(1)
strtxt = Right(strtxt, 2) & "/" & Left(strtxt, 4) & "/" & Mid(strtxt, 8, 2) & "/" & Mid(strtxt, 5, 3)
.Hyperlinks.Add Anchor:=.Duplicate, Address:="Address" & strtxt & "/0.pdf", TextToDisplay:=.Text
.End = .Fields(1).Result.End
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
How to collapse correctly to make this work. Currently it hyperlinks all in the doccument instead selection.

As far as I can tell, the problem is basically that the found range's end needs to be increased by 1 when the hyperlink is inserted. But I believe you also have to check that you have not gone past the original Selection.Range end, so you need an additional test.
This seemed OK in Tables, but (a) I am currently testing in Mac Word 2011, which may well be different, and (b), if you actually select a column or noncontiguous ranges, you would have to work a lot harder to make the changes only in the selection (because of well-known lack of support for such selections).
Sub fandr()
Const strText As String = "String String1"
Dim dr As Word.Range
Dim sr As Word.Range
Set sr = Selection.Range
'Debug.Print sr.Start, sr.End
Set dr = sr.Duplicate
' Try to deal with the problem where Find fails to find
' the Find text if it is exactly the same as the selection
sr.Collapse wdCollapseStart
With sr.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = strText
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
Do While .Execute(Replace:=False)
If sr.InRange(dr) Then
'Debug.Print sr.Start, sr.End, dr.Start, dr.End
strtxt = Split(.Text, " ")(1)
strtxt = Right(strtxt, 2) & "/" & Left(strtxt, 4) & "/" & Mid(strtxt, 8, 2) & "/" & Mid(strtxt, 5, 3)
sr.Hyperlinks.Add Anchor:=sr, Address:="Address" & strtxt & "/0.pdf", TextToDisplay:=.Text
sr.Collapse wdCollapseEnd
sr.End = sr.End + 1
sr.Start = sr.End
'Debug.Print sr.Start, sr.End, dr.Start, dr.End
Else
Exit Do
End If
Loop
End With
Set sr = Nothing
Set dr = Nothing
End Sub

So I have changed a few things. Somehow the Range was getting messed up after adding the HyperLink. so I just reset the SearchRange after adding the hyperlink.
This will work perfectly if the selection is not part of a Table I have added some checks to see if its in side the table but dont have time now to complete the cell shift.
Sub SearchTextAddHyperLink()
Dim SearchRange As Range
Dim OriginalRange As Range
Dim FoundRange As Range
Set SearchRange = Selection.Range
Set OriginalRange = Selection.Range
Dim strtxt As String
Dim SearchText As String
Dim CellPosition As String
SearchText = "String String1"
With SearchRange
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = SearchText
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
End With
Do While .Find.Execute
'.Select
If .Find.Found = True Then
Set FoundRange = SearchRange
FoundRange.Select
strtxt = Split(.Text, " ")(1)
strtxt = Right(strtxt, 2) & "/" & Left(strtxt, 4) & "/" & Mid(strtxt, 8, 2) & "/" & Mid(strtxt, 5, 3)
.Hyperlinks.Add Anchor:=.Duplicate, Address:="Address" & strtxt & "/0.pdf", TextToDisplay:=.Text
If Not FoundRange.Information(wdWithInTable) Then
'Resetting the SearchRange for outside a table
'For some reason the Hyperlink messes up the Range
'Len(SearchText) + 1 just caters for the changing the Search Text
'and adding an additional character to move passed the hyperlink
SearchRange.Start = FoundRange.End + Len(SearchText) + 1
SearchRange.End = OriginalRange.End
Else
'Resetting the SearchRange for inside a table
'Need to then be clever with determinign which cell you are in and then moving to the next cell
'SearchRange.Start = FoundRange.End 'Len(SearchText) + 1
'SearchRange.End = OriginalRange.End
End If
End If
'Just to check the SearchRange
SearchRange.Select
Loop
End With
End Sub
NOTE: Also, remember to also Dim all your variables going forward.

Related

VB.NET MS Word - How to store a ms word table cell corresponding to a FOUND word.range into a table.Cell variable

I am trying to find a string in my word document header table. I can find the range but I want to store the specific cell which this found range is located in into a table.cell variable.
How can I do it?
In VBA, for example, to retrieve the cell's table#, row # & column #:
Sub GetCellRef()
Application.ScreenUpdating = False
Dim Rng As Range, t As Long, r As Long, c As Long
With ActiveDocument.Sections.First.Headers(wdHeaderFooterPrimary)
Set Rng = .Range
With .Range
With .Find
.Text = "Text to Find"
.Forward = True
.Wrap = wdFindStop
.MatchCase = False
.MatchWholeWord = True
.Execute
End With
If .Find.Found = True Then
If .Information(wdWithInTable) = True Then
Rng.End = .Cells(1).Range.End - 1
t = Rng.Tables.Count
Rng.Start = .Start
r = .Cells(1).RowIndex
c = .Cells(1).ColumnIndex
MsgBox Chr(34) & Rng.Text & Chr(34) & vbCr & _
"Found in table " & t & " at row " & r & " column " & c
End If
End If
End With
End With
Application.ScreenUpdating = True
End Sub

Find first instance of the acronym

Any help would be awesome. I have a macro that finds acronyms and applies a spell out of the acronym with the acronym in parenthesis. It is applying the spell out and acronym once but randomly. I need the macro to identify the first instance and apply the spell out only to that first instance. So if the first instance should look like this:
Be Right Back (BRB) some text BRB some text BRB
Right know it looks like this: BRB some text Be Right Back (BRB) some text BRB
The macro has the code " .Execute Replace:=wdReplaceOne" but it doesn't seem to be working.
Here's the code I am using:
Sub AcronymManager()
Application.ScreenUpdating = False
Dim FRDoc As Document, FRList As String, j As Long, StrExp As String, StrAcc As String
'Load the strings from the reference doc into a text string to be used as an array.
Set FRDoc = ThisDocument
'Alternative code to use a different document the reference doc:
'Set FRDoc = Documents.Open("C:\Users" & Environ("UserName") & "\Documents\AcronymList.doc")
If ActiveDocument = FRDoc Then
MsgBox "Error: Cannot process this document - it's the source document", vbCritical
Exit Sub
End If
FRList = FRDoc.Range.Text
If FRDoc <> ThisDocument Then FRDoc.Close wdDoNotSaveChanges
Set FRDoc = Nothing
With ActiveDocument.Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Highlight = True
.MatchWholeWord = True
.MatchCase = True
.Wrap = wdFindContinue
'Process each word from the Check List. Tab-delimited strings are assumed, formatted as:
'Find text <Tab> Replace text
For j = 0 To UBound(Split(FRList, vbCr)) - 1
StrExp = Split(Split(FRList, vbCr)(j), vbTab)(0)
StrAcc = Split(Split(FRList, vbCr)(j), vbTab)(1)
.Text = StrExp
.Replacement.Text = StrAcc
.Execute Replace:=wdReplaceAll
.Text = "(" & StrAcc & ")"
.Execute Replace:=wdReplaceAll
.Text = StrAcc & "^w" & StrAcc
.Execute Replace:=wdReplaceAll
.Text = StrAcc
.Replacement.Text = StrExp & " (" & StrAcc & ")"
.Execute Replace:=wdReplaceOne
Next
End With
Application.ScreenUpdating = True
End Sub

Macro to Replace Pronouns with Conditional Merge Field

I need a macro that replaces his/her or he/she with a conditional merge field. Thanks to another website, I was able to replace these pronouns with a merge field, but not a conditional merge field without crashing MS Word. Below is the code that I used.
Sub TestAddIf()
Dim doc As Word.Document
Dim mRng As Range
Set doc = ActiveDocument
Set mRng = ActiveDocument.Range
With oRng.Find
Do While .Execute(FindText:="he")
doc.MailMerge.Fields.AddIf mRng, _
MERGEFIELD:="""Client_Sex""", Comparison:=wdMergeIfEqual, CompareTo:="M", _
truetext:="he", _
falsetext:="she"
mRng.Collapse wdCollapseEnd
Loop
End With
End Sub
Try the following macro, which deals with 'he', 'his', 'him', and 'male' throughout the document (delete the ',male' & ',female' terms if you don't want them).
Sub Demo()
Application.ScreenUpdating = False
Dim Rng As Range, RngFld As Range, StrFnd As String, StrRep As String, StrCode As String, i As Long, j As Long
StrM = "he,his,him,male": StrF = "she,her,her,female"
With ActiveDocument
For i = 0 To UBound(Split(StrM, ","))
StrCode = "IFX= ""M"" """ & Split(StrM, ",")(i) & """ """ & Split(StrF, ",")(i) & """"
j = Len(StrCode) + 4
Set Rng = .Range(0, 0)
.Fields.Add Range:=Rng, Type:=wdFieldEmpty, Text:=StrCode, PreserveFormatting:=False
Rng.End = Rng.End + j
.Fields.Add Range:=Rng.Characters(5), Type:=wdFieldEmpty, Text:="MERGEFIELD Client_Sex", PreserveFormatting:=False
Rng.Cut
With .Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindContinue
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.Text = Split(StrM, ",")(i)
.Replacement.Text = "^c"
.Execute Replace:=wdReplaceAll
End With
Next
End With
Application.ScreenUpdating = True
End Sub

Trying to use VBA to Automate Document Splitting in Word

I am trying to VBA my way into automating a process that my team and myself currently do manually-- taking a Word document and splitting it into multiple documents based on H1 sections (by which I mean, if a doc has 6 H1s, then we wind up with 6 documents).
I have found some code that works well enough, but there are a couple pieces that I can't quite puzzle out.
Getting the footers from my original document to show up in the subdocuments, and
adding a sequential number at the start of each file name.
The former requirement is pretty simple-- my original doc has a footer on it, and I'd like the documents that the code spits out to have the same footer. Right now, the resulting files have blank footers. The latter requirement is that I ultimately would like the new files to have file names with the format "XX - [HeadingText].docx". The code I'm using gets me the heading text just fine, but I can't seem to plug in the sequential numbering.
Here's the code I'm using; any help would be appreciated!
Sub SeparateHeadings()
'
' SeparateHeadings Macro
'
'
Application.ScreenUpdating = False
Dim StrTmplt As String, StrPath As String, StrFlNm As String, Rng As Range, Doc As Document, i As Long
Dim iTemp As Integer
With ActiveDocument
StrTmplt = .AttachedTemplate.FullName
StrPath = .Path & "\"
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Style = "Heading 1"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
Do While .Find.Found
Set Rng = .Paragraphs(1).Range.Duplicate
With Rng
StrFlNm = Replace(.Text, vbCr, "")
For i = 1 To 255
Select Case i
Case 1 To 31, 33, 34, 37, 42, 44, 46, 47, 58 - 63, 91 - 93, 96, 124, 147, 148
StrFlNm = Replace(StrFlNm, Chr(i), "")
End Select
Next
iTemp = iTemp + 1
Do
If .Paragraphs.Last.Range.End = ActiveDocument.Range.End Then Exit Do
Select Case .Paragraphs.Last.Next.Style
Case "Heading 1"
Exit Do
Case Else
.MoveEnd wdParagraph, 1
End Select
Loop
End With
Set Doc = Documents.Add(Template:=StrTmplt, Visible:=False)
With Doc
.Range.FormattedText = Rng.FormattedText
.SaveAs2 FileName:=StrPath & StrFlNm, Fileformat:=wdFormatXMLDocument, AddToRecentFiles:=False
.Close False
End With
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
End With
Set Doc = Nothing: Set Rng = Nothing
Application.ScreenUpdating = True
End Sub
Try:
Sub SplitDocByHeading1()
Application.ScreenUpdating = False
Dim StrTmplt As String, StrPath As String, StrFlNm As String
Dim Rng As Range, i As Long, j As Long, Doc As Document
Const StrNoChr As String = """*./\:?|"
With ActiveDocument
StrTmplt = .FullName
StrPath = .Path & "\"
'Convert auto numbering to static numbering
.ConvertNumbersToText (wdNumberAllNumbers)
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Replacement.Text = ""
.Style = wdStyleHeading1
.Format = True
.Forward = True
.Wrap = wdFindStop
.Execute
End With
Do While .Find.Found
Set Rng = .Duplicate: i = i + 1
StrFlNm = Split(Rng.Paragraphs(1).Range.Text, vbCr)(0)
For j = 1 To Len(StrNoChr)
StrFlNm = Replace(StrFlNm, Mid(StrNoChr, j, 1), "_")
Next
StrFlNm = Format(i, "00") & "_" & StrFlNm & ".docx"
Set Rng = Rng.GoTo(What:=wdGoToBookmark, Name:="\HeadingLevel")
Set Doc = Documents.Add(Template:=StrTmplt, Visible:=False)
With Doc
.Range.FormattedText = Rng.FormattedText
.SaveAs2 FileName:=StrPath & StrFlNm, Fileformat:=wdFormatXMLDocument, AddToRecentFiles:=False
.Close False
End With
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
End With
Set Doc = Nothing: Set Rng = Nothing
Application.ScreenUpdating = True
End Sub

Select certain page on condition in vba

I am writing a script that extract tables from Word file as copies it to a worksheet in Excel. However, the Word files I received do not have the same format and the tables I need are not always on the same page. Hence I cannot use the regular table index.
Each table is on a different page and only on that page there somewhere is a text string (may or may not be in the table itself) like 'material/material list'. What I'd like to do is scan each page of the Word document for a certain textstring and only if that string is present, use the corresponding table on that page. Is this possible and how would I go about this?
A complication of the inconsistent formatting is that on some pages, the data is not even in a table so for those files I'd like an alert if the trigger word is found on a page but no table is there.
Edited:
I have tried to redefine the range considered. My hope is that this is the easiest method; see where the keyword occurs and then use the first table after that. However this does not seem to work.
With ActiveDocument.Content.Find
.Text = "Equipment"
.Forward = True
.Execute
If .Found = True Then Set aRange = ActiveDocument.Range(Start:=0, End:=0)
End With
Edit:
I tried to combine the code from macropod with a vba in Excel that copies the table to the worksheet.
Sub LookForWordDocs()
Dim FolderName As String
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
On Error Resume Next
FolderName = .SelectedItems(1)
Err.Clear
On Error GoTo 0
End With
Dim sFoldPath As String: sFoldPath = FolderName ' Change the path. Ensure that your have "\" at the end of your path
Dim oFSO As New FileSystemObject ' Requires "Microsoft Scripting Runtime" reference
Dim oFile As File
' Loop to go through all files in specified folder
For Each oFile In oFSO.GetFolder(sFoldPath).Files
' Check if file is a word document. (Also added a check to ensure that we don't pick up a temp Word file)
If ((InStr(1, LCase(oFSO.GetExtensionName(oFile.Path)), "doc", vbTextCompare) > 0) Or _
(InStr(1, LCase(oFSO.GetExtensionName(oFile.Path)), "docx", vbTextCompare) > 0)) And _
(InStr(1, oFile.Name, "~$") = 0) And _
((InStr(1, oFile.Name, "k") = 1) Or (InStr(1, oFile.Name, "K") = 1)) Then
' Call the UDF to copy from word document
ImpTable oFile
End If
Next
End Sub
Sub ImpTable(ByVal oFile As File)
Dim oWdApp As New Word.Application
Dim oWdDoc As Word.Document
Dim oWdTable As Word.Table
Dim oWS As Excel.Worksheet
Dim lLastRow$, lLastColumn$
Dim s As String
s = "No correct table found"
With Excel.ThisWorkbook
Set oWS = Excel.Worksheets.Add
On Error Resume Next
oWS.Name = oFile.Name
On Error GoTo 0
Set sht = oWS.Range("A1")
Set oWdDoc = oWdApp.Documents.Open(oFile.Path)
oWdDoc.Activate
'Application.ScreenUpdating = False
Dim StrFnd As String, Rng As Word.Range, i As Long, j As Long
j = 0
StrFnd = "equipment"
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = StrFnd
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
Do While .Find.Found
i = .Information(wdActiveEndAdjustedPageNumber)
Set Rng = Word.ActiveDocument.Goto(What:=wdGoToPage, Name:=i)
Set Rng = Rng.Goto(What:=wdGoToBookmark, Name:="\page")
If Rng.Tables.Count > 0 Then
With Rng.Tables(1)
Set oWdTable = Rng.Tables(1)
oWdTable.Range.Copy
sht.PasteSpecial xlPasteValues, xlPasteSpecialOperationNone
j = 1
End With
End If
.Start = Rng.End
.Find.Execute
Loop
End With
If j = 0 Then sht.Value = s
'Application.ScreenUpdating = True
oWdDoc.Close savechanges:=False
oWdApp.Quit
End With
Set oWS = Nothing
Set sht = Nothing
Set oWdDoc = Nothing
Set oWdTable = Nothing
Set Rng = Nothing
End Sub
For the first file, the code works fine. However on the second run I get a run-time error "The remote Server Machine does not Exist or is unavailable" on line
"Word.ActiveDocument.Range". I added a couple of qualifications for elements but this still did not solve the problem. Am I missing another line?
BTW When I place "Word" before ActiveDocument.Range the code does not work any more.
Since you've changed the text from 'material/material list' to 'Equipment', it's a bit hard to know quite what you want. Try something along the lines of:
Sub Demo()
Application.ScreenUpdating = False
Dim StrFnd As String, Rng As Range, i As Long
StrFnd = InputBox("What is the Text to Find")
If Trim(StrFnd) = "" Then Exit Sub
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = StrFnd
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = True
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
Do While .Find.Found
i = .Information(wdActiveEndAdjustedPageNumber)
Set Rng = ActiveDocument.GoTo(What:=wdGoToPage, Name:=i)
Set Rng = Rng.GoTo(What:=wdGoToBookmark, Name:="\page")
If Rng.Tables.Count > 0 Then
MsgBox Chr(34) & StrFnd & Chr(34) & " and table found on page " & i & "."
With Rng.Tables(1)
'process this table
End With
Else
MsgBox Chr(34) & StrFnd & Chr(34) & " found on page " & i & " but no table."
End If
.Start = Rng.End
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
End Sub
Note: the above code will test all pages on which the Find text is found.