Replace and add at end of the line - vba

I need to replace some starting text with another one and add at the end another text. This is a starting example:
- This is a phrase that match
Another - Phrase
Yes another - one
- This also match
The result i want to have is:
$This is a phrase that match%
Another - Phrase
Yes another - one
$This also match%
So replace "- " with "$" (only if is the first two character of the sentence) and add at the end of the line, if match, "%"
I have search and the the replace function work but i don't know how to add the end of line:
With Selection.Find
.ClearFormatting
.Text = "- "
.Replacement.Text = "$"
.Execute Replace:=wdReplaceAll, Forward:=True, Wrap:=wdFindContinue
End With
I have see there is a InsetAfter method but it create a new line, or i have wrong implemented. Suggestions? Thanks

You don't even need a macro for this! All you need is a wildcard Find/Replace, where:
Find = ^13- ([!^13]#)^13
Replace = ^p$\1%^p

Related

How to replace with multiline string?

The code for find and replace is working when replacement string is short (in a line) but causing problem when replacement string is multiline string (may be without new line char).
With WordDoc.Content.Find
.Text = "<<audit_standard>>"
.Replacement.Text = Range("B9")
.Wrap = 1
.Execute Replace:=1
End With
This works when Cell B9 content is short and can be fit in a single line in Word file.
Neither a Find expression nor a Replace expression can include a line break. Wrapped lines in the source are of no consequence however, unless they are more than 255 characters long (the F/R string-length limit). What might be able to use is:
Range("B9").Copy
With WordDoc.Content.Find
.Text = "<<audit_standard>>"
.Replacement.Text = "^c"
.Wrap = 1
.Execute Replace:=1
End With
Alternatively, to insert a line break (not a paragraph break) but otherwise discard the source formatting:
With WordDoc.Content.Find
.Text = "<<audit_standard>>"
.Replacement.Text = Replace(Range("B9").Text, Chr(10), "^l")
.Wrap = 1
.Execute Replace:=1
End With
If you want a paragraph break instead of a line break, replace ^l with ^p.
After researching about it little more, I found an easy and elegant solution.
I do not see any problem with my new approach for now. It's working perfectly.
In word document I created a bookmark named "audit_standard" for <<audit_standard>> text.
and then wrote below code in VBA for replacement.
WordDoc.Bookmarks("audit_standard").Range.text = Range("B9").Value

Finding and Replacing with VBA for Word overwrites previous style

I'm writing a VBA script to generate word documents from an already defined template. In it, I need to be able to write headings along with a body for each heading. As a small example, I have a word document that contains only <PLACEHOLDER>. For each heading and body I need to write, I use the find-and-replace feature in VBA to find <PLACEHOLDER> and replace it with the heading name, a newline, and then <PLACEHOLDER> again. This is repeated until each heading name and body is written and then the final <PLACEHOLDER> is replaced with a newline.
The text replacing works fine, but the style I specify gets overwritten by the next call to the replacement. This results in everything I just replaced having the style of whatever my last call to my replacement function is.
VBA code (run main)
Option Explicit
Sub replace_stuff(search_string As String, replace_string As String, style As Integer)
With ActiveDocument.Range.Find
.Text = search_string
.Replacement.Text = replace_string
.Replacement.style = style
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchWholeWord = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceAll
End With
End Sub
Sub main()
Dim section_names(2) As String
section_names(0) = "Introduction"
section_names(1) = "Background"
section_names(2) = "Conclusion"
Dim section_bodies(2) As String
section_bodies(0) = "This is the body text for the introduction! Fetched from some file."
section_bodies(1) = "And Background... I have no issue fetching data from the files."
section_bodies(2) = "And for the conclusion... But I want the styles to 'stick'!"
Dim i As Integer
For i = 0 To 2
' Writes each section name as wsStyleHeading2, and then the section body as wdStyleNormal
Call replace_stuff("<PLACEHOLDER>", section_names(i) & Chr(11) & "<PLACEHOLDER>", wdStyleHeading2)
Call replace_stuff("<PLACEHOLDER>", section_bodies(i) & Chr(11) & "<PLACEHOLDER>", wdStyleNormal)
Next i
Call replace_stuff("<PLACEHOLDER>", Chr(11), wdStyleNormal)
End Sub
Input document: A word document with only <PLACEHOLDER> in it.
<PLACEHOLDER>
Expected Output:
I expect that each heading will be displayed in the style I specified and can be viewed from the navigation pane like this:
Actual Output: However what I actually get is everything as wdStyleNormal style like this:
I think the problem can be solved by inserting a paragraph break between every style transition, but when I try using vbCrLF or Chr(10) & Chr(13) or vbNewLine instead of the chr(11) I am using now, Each line begins with a boxed question mark like this:
Update from discussion in comments on another answer. The problem described below applies to Word 2016 and earlier. Starting in Office 365 (and probably Word 2019, but that's not been confirmed) the Replace behavior has been changed to "convert" ANSI 13 to a "real" paragraph mark, so the problem in the question would not occur.
Answer
The reason for the odd formatting behavior is the use of Chr(11), which inserts a new line (Shift + Enter) instead of a new paragraph. So a paragraph style applied to any part of this text formats the entire text with the same style.
In this particular case (working with Replace), vbCr or the equivalent Chr(13) also don't work because these are not really Word's native paragraph. A paragraph is much more than just ANSI code 13 - it contains paragraph formatting information. So, while the code is running, Word is not really recognizing these as true paragraph marks and the paragraph style assignment is being applied to "everything".
What does work is to use the string ^p, which in Word's Find/Replace is the "alias" for a complete paragraph mark. So, for example:
replace_stuff "<PLACEHOLDER>", section_names(i) & "^p" & "<PLACEHOLDER>", wdStyleHeading2
replace_stuff "<PLACEHOLDER>", section_bodies(i) & "^p" & "<PLACEHOLDER>", wdStyleNormal
There is, however, a more efficient way to build a document than inserting a placeholder for each new item and using Find/Replace to replace the placeholder with the document content. The more conventional approach is to work with a Range object (think of it like an invisible selection)...
Assign content to the Range, format it, collapse (like pressing right-arrow for a selection) and repeat. Here's an example that returns the same result as the (corrected) code in the question:
Sub main()
Dim rng As Range
Set rng = ActiveDocument.content
Dim section_names(2) As String
section_names(0) = "Introduction"
section_names(1) = "Background"
section_names(2) = "Conclusion"
Dim section_bodies(2) As String
section_bodies(0) = "This is the body text for the introduction! Fetched from some file."
section_bodies(1) = "And Background... I have no issue fetching data from the files."
section_bodies(2) = "And for the conclusion... But I want the styles to 'stick'!"
Dim i As Integer
For i = 0 To 2
BuildParagraph section_names(i), wdStyleHeading2, rng
BuildParagraph section_bodies(i), wdStyleNormal, rng
Next i
End Sub
Sub BuildParagraph(para_text As String, para_style As Long, rng As Range)
rng.Text = para_text
rng.style = para_style
rng.InsertParagraphAfter
rng.Collapse wdCollapseEnd
End Sub
The problem is caused by your use of Chr(11) which is a manual line break. This results in all of the text being in a single paragraph. When the paragraph style is applied it applies to the entire paragraph.
Replace Chr(11) with vbCr to ensure that each piece of text is in a separate paragraph.

Replace string and rest of line with other string

So here's what I want to do:
I have a string origStr, which is at the beginning of a line in a Word document. After origStr is an unknown value (e.g. 23 or 2,6)
I want to find that string and replace the value after with another known value, but keep the string.
Example in my Word document:
Diam. diastole, mm: 53
[Running VBA makro where user input is 54,3]
Expected Result:
Diam. diastole, mm: 54,3
Actual result:
Diam. diastole, mm: 54,3 53
So here's what i got:
origStr = LArray(i, j - 1).Caption & ": *"
replStr = LArray(i, j - 1).Caption & ": " & TBArray(i, j).Text
With ActiveDocument.Content.Find
.MatchWildcards = True
.ClearFormatting
.Text = origStr
.Replacement.ClearFormatting
.Replacement.Text = replStr
.Execute Replace:=wdReplaceAll, Forward:=True, Wrap:=wdFindStop
End With
Why isn't my old value being deleted?
Thanks in advance!
Word uses "lazy" pattern matching which is good in this case because otherwise it would just replace the rest of your entire document. Vincent G gave a solution for one word (no more than one space in the rest of the line), here is something more general:
To get Word to replace everything until the end of the line, you need to include the end of the line into the search string. ^l or ^11 is the control code for new line (shift+enter), ^12 is page or section break, ^13 is carriage return.
This is the most "recent" list I found.
So "yourtext*^11" would match everything from "yourtext" until the next new line and so on.
Depending on your formatting, it could be either one of the above so you have to be careful. If you replace "*^12" but your lines end with new line, you will replace the whole paragraph.
To catch all of them, you can group them: yourtext*[^11^12^13] will match everything until the next new line or carriage return. However if we replace that, the end of the line will be replaced as well so we have to include it in the replacement text. How do we know what it was?
We can use () to define a submatch and \1, \2 etc to use these submatches in the replacement text:
origStr = LArray(i, j - 1).Caption & ": *([^11^12^13])"
replStr = LArray(i, j - 1).Caption & ": " & TBArray(i, j).Text & "\1"
Example:
before:
after replacing with origStr = "yourtext*([^11^12^13])" and replStr = "yourtext newtext\1":
Note: These expressions also work with the Find and Replace dialog, just make sure "Use Wildcards" is enabled
Its not really a VBA problem, the same happening in "Find and Replace" dialog.
Replace your original string with:
origStr = LArray(i, j - 1).Caption & ": <*>"

VBA Compare positions of two words in a Word document

I'm writing a module for defining acronyms in Word documents. The script gets the acronym and definition from an Excel document. What I'm having trouble with is comparing the location of the first instance of the acronym with the location of the first instance of the full definition.
Ultimately, I need to make sure the first instance of the acronym occurs immediately after the first instance of the definition, enclosed in parentheses. After this is done, the script will need to remove subsequent instances of the definition, so I also need to figure out how to remove all but the first instance of a definition.
The end result should look something like this:
....This document is about software as a service (SaaS). SaaS is software that is hosted by someone else. Rather than installing it on your own computer, you access it through a Web browser. There are many types of SaaS.
....
How can I get the positions of these two elements and or compare their positions?
In the example above, how would I find the first instance of "SaaS" and make sure it occurred exactly two positions after (space, open parentheses) the definition (assuming the definition actually appears in the document)?
'Selects first instance of acronym. Get start and end positions of first instance of acronym.
Selection.HomeKey Unit:=wdStory
Selection.Find.Execute Acronym 'Acronym is a variable. Now that it's selected, I need to get it's start position (or the position of the cursor if the cursor is at the start of the acronym) or find a way to compare it's position to the UserSelection variable.
'Is the definition in the document?
'If no, add definition before first instance of acronym.
'If yes, get start and end positions of first instance of definition.
'Is end position of first instance of definition adjacent to start position of first instance of acronym? If not, which is first?
'If definition is first, add acronym behind definition.
'If acronym is first, add definition in front of acronym and delete remaining instances of definition.
'Highlights all instances of the acronym in green
With ActiveDocument.Content.Find
.MatchCase = True
.MatchWholeWord = False
With .Replacement
.Highlight = True
End With
.Execute Replace:=wdReplaceAll, Wrap:=wdFindContinue, FindText:=Acronym, ReplaceWith:=Acronym
End With
Any help or insight would be appreciated, as I'm completely at a loss and having no luck with Google.
-Vince
I think the following code snippet can help you:
Sub example(acronym, definition)
Selection.Find.ClearFormatting
With Selection.Find
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchAllWordForms = False
End With
ActiveDocument.Range(0, 0).Select ' go to beginning of document
Selection.Find.Text = acronym
Selection.MatchSoundsLike = False
If (Not Selection.Find.Execute) Then
' acronym not found in this document
Exit Sub
End If
ActiveDocument.Range(0, 0).Select ' go to beginning of document
Selection.Find.Text = definition
Selection.MatchCase = False
Selection.MatchSoundsLike = True
While (Selection.Find.Execute)
'
Selection.Delete ' delete all definitions
'
Wend
ActiveDocument.Range(0, 0).Select ' go to beginning of document
Selection.Find.Text = acronym
Selection.MatchSoundsLike = False
If (Selection.Find.Execute) Then
Selection.InsertBefore "(" & definition & ")"
End If
End Sub
Note: I also found that authors make mistakes in the definitions (minor variations) and even an extra unintended space messes up the find.

WORD VBA Count Wildcard Search Hits

Hi i have the codes below that is already working perfectly. What i can't figure out is how to count the number of times a wildcard search finds a match. Can anyone tell me how i can go about this? The codes are as follows:
Sub findfunction()
If (findHL(activedocument.Content, "[aeiou]")) = True Then MsgBox "Highlight vowels Done", vbInformation + vbOKOnly, "Vowels Highlight Result"
If (findHL(activedocument.Range, "<wa*>")) = True Then MsgBox "Highlight words beginning with WA", vbInformation + vbOKOnly, "Prefix Find Result"
End Sub
Function findHL(r As Range, s As String) As Boolean
Options.DefaultHighlightColorIndex = wdRed
r.Find.Replacement.highlight = True
r.Find.Execute FindText:=s, MatchWildcards:=True, Wrap:=wdFindContinue, Format:=True, replace:=wdReplaceAll
findHL = True
End Function
Any help would greatly be appreciated. Thanks guys!
I think you just need a static Counter field defined at the top of your module - i.e. not within any sub or function (which is what makes it static):
dim MatchCounter as long
Just initialize to zero at the appropriate place and have your matching function increment on each match. (Could also wrap this in a small Class if the initialization logic / update logic is spread around & hard to pin down).