Duplicate and alter text in a Word document using VBA Scripts - vba

I would like to alter a Word document by using a Word VBA script. The Word document consists of bibliographic records. I would like to duplicate the first occurrence of field \TRF of each record and to change its field label (into \OTT). I recorded a VBA Script and it works fine if I position the cursor in front of the first occurrence of \TRF. I would like the VBA Script to repeat the alterations in the entire document but to only alter all first occurrences of \TRF. Recording a VBA Script with keyboard keys (Ctrl+F) plus text didn’t work. And my attempts to add vba code to the VBA Script where not successful.. What is the correct syntax I have to add to my VBA Script?
Original text:
(this example displays one record, the document contains more records)
\PPN 375496173
\TTT Pour un autre regard sur l'art beti / Bienvenu Cyrille Bela
\TRF Cameroon
\TRF Beti
\TRF sculpture
\TRF visual arts
\DAT 15-08-14
\DAV 20140815
\SIG AFRIKA 47231
\ISP text
\END
Text after alteration
\PPN 375496173
\TTT Pour un autre regard sur l'art beti / Bienvenu Cyrille Bela
\TRF Cameroon
\OTT Cameroon
\TRF Beti
\TRF sculpture
\TRF visual arts
\DAT 15-08-14
\DAV 20140815
\SIG AFRIKA 47231
\ISP text
\END
Incorrect macro:
Sub MacroCountry()
' MacroCountry Macro
With ActiveDocument.Content.Find
'Search for \PPN (beginning of the record) and then search for \TRF
.Text = "\PPN"
.Text = "\TRF"
'the selection part of the Macro works fine, it selects the line, duplicates it and changes the field label
Selection.EndKey Unit:=wdLine, Extend:=wdExtend
Selection.Copy
Selection.MoveRight Unit:=wdWord, Count:=1
Selection.TypeParagraph
Selection.MoveUp Unit:=wdLine, Count:=1
Selection.PasteAndFormat (wdFormatOriginalFormatting)
Selection.Delete Unit:=wdCharacter, Count:=1
Selection.MoveUp Unit:=wdLine, Count:=1
Selection.MoveRight Unit:=wdWord, Count:=2, Extend:=wdExtend
Selection.TypeText Text:="\Ott "
End With
Loop
End Sub

I'm trying to find out a little bit more about MS Word framework so I used this as exercise. You could try this. Precondition is that all lines are ending with newlines so each line is a paragraph.
Sub InsertLines()
Dim rng As Range
Dim i As Integer
Dim doc As Document
Dim line As String
Dim inBlock As Boolean, found As Boolean
Set doc = ThisDocument
i = 1
While i < ThisDocument.Paragraphs.Count
line = doc.Paragraphs(i).Range.Text
If InStr(line, "\PPN") > 0 Then
inBlock = True
found = False
End If
If InStr(line, "\END") > 0 Then
inBlock = False
End If
If inBlock And Not found Then
If InStr(line, "\TRF") > 0 Then
doc.Paragraphs(i).Range.InsertAfter "\OTT " & Mid(line, 5)
found = True
End If
End If
i = i + 1
Wend
End Sub
I'm sure there are more elegant solutions but I hope this is a solution at all. I tried a little bit with RegExp and Find object but this is more straightforward.

Related

MS Word: Getting the actual ASCII code of an inserted symbol

I am trying to write a VBA code for MS-Word to remove rows with the unticked symbol from a table.
To do that, I need MS-Word to recognize it and differentiate between it and the ticked symbol. But unlike Excel, MS-Word seems to be bad at it.
To focus on the problem, I inserted the symbols, but I can not get the correct ASCII code of the character I have just inserted.
Here is what I tried:
Sub SymbolsTest()
Selection.InsertSymbol 163, "Wingdings 2", True 'Insert unticked
Selection.MoveRight Unit:=wdCharacter, Count:=-1, Extend:=wdExtend 'Select it
Debug.Print AscW(Selection.Text) & " " & Selection.Text 'Ask for ASCII
Selection.Collapse 0
Selection.InsertSymbol 82, "Wingdings 2", True 'Insert ticked
Selection.MoveRight Unit:=wdCharacter, Count:=-1, Extend:=wdExtend 'Select it
Debug.Print AscW(Selection.Text) & " " & Selection.Text 'Ask for ASCII
End Sub
The output is:
40 (
40 (
I would expect it to be:
163 ?
82 ?
I also tried ?Selection.Characters(1) = Selection.Characters(2) in the immediate window while selecting both of them, and I got True
Any help would be appreciated.
As far as I know
there is no simple way to get the character's code point or font name directly using any of the properties of the Selection or Range
In this situation, Word always uses the code point 40 (")"), and internally, it does does store the name of the font you specified and a Unicode codepoint (e.g. U+F052 for the checked box).
Two things you can do. If the character is not 40, assume it already has the correct codepoint (although I am not certain about that). But if not,
retrieve the .XML or .WordOpenXML of the Selection or Range and look for the relevant element, e.g. ><w:sym w:font="Wingdings 2" w:char="F052"/> in both the old-style .XMLand the newer .WordOpenXML. You could either search for the text <w:sym and look for the font and codepoint in the following text, or "do it properly" using an XML parser. In that case, it may be useful to know that F052 either means "the Unicode character with code point F052, or it means "it's F000 + the code point in the original character set", i.e. Wingdings 2 in this case.
e.g. one way would be to make a reference in the VB Editor's Tools-References to the Microsoft XML library (in this case 6.0) and use code along these lines:
Sub getCharFontAndCodepoint()
Dim xdoc As MSXML2.DOMDocument60
Dim xSymNodes As MSXML2.IXMLDOMNodeList
Set xdoc = New MSXML2.DOMDocument60
xdoc.async = False
If xdoc.LoadXML(Selection.XML) Then
xdoc.SetProperty _
"SelectionNamespaces", _
"xmlns:w='http://schemas.microsoft.com/office/word/2003/wordml'"
Set xSymNodes = xdoc.SelectNodes("//w:sym/#w:font")
If xSymNodes.Length > 0 Then
Debug.Print xSymNodes(0).NodeValue
End If
Set xSymNodes = xdoc.SelectNodes("//w:sym/#w:char")
If xSymNodes.Length > 0 Then
Debug.Print xSymNodes(0).NodeValue
End If
End If
Set xSymNodes = Nothing
Set xdoc = Nothing
End Sub
or, if you only need the codepoint, copy the character and use paste special to paste it using the Unformatted Unicode Text format, e.g.
Selection.Copy
Selection.PasteSpecial link:=False, DataType:=22 ' There does not seem to be a named enum for this particular format
Selection.MoveLeft Unit:=WdUnits.wdCharacter, Count:=1, Extend:=WdMovementType.wdExtend
Debug.Print Hex(AscW(Selection))
Selection.Document.Undo

VBA Word - Using If Function to Insert Text, And Change Font of The Text

I'm a beginner at coding, so please bear with me. Is there any way to use the function If to insert text (using TypeText), and then change the font of that text added using VBA Word?
So I'll give you some information on what I am working on; I am using the following code to count the number of spelling mistakes in a document.
Sub countErrors()
MsgBox (ActiveDocument.SpellingErrors.count)
End Sub
What I would like to do is use an If function to the number of spelling mistakes present. If there are any spelling mistakes I want to insert text at the top of the document saying "REJECTED " with font in red, bold and size 14. Is there any way to do this using the If function?
I tried adding the following to the above code;
Sub countErrors()
Msgbox (ActiveDocument.SpellingErrors.count)
If SpellingErrors <= 1 then
Selection.HomeKey unit:=wdStory
With Selection
.Font.Size = 14
.Font.ColorIndex = wdRed
.Font.Bold = True
End With
Selection.TypeText ("REJECTED ")
End If
End Sub
The code just counts the number of spelling mistakes and displays a MsgBox with it, and then that's where the code ends -- it doesn't add any text, etc.
Can someone please let me know where I am going wrong? This is extremely frustrating.
Thank you in advance.
Your code needs to check if SpellingErrors is greater than zero.
Sub CountErrors()
MsgBox "The document currently has " & ActiveDocument.SpellingErrors.Count & " spelling error(s)."
If ActiveDocument.SpellingErrors.Count > 0 Then
Selection.HomeKey unit:=wdStory
With Selection
.Font.Size = 14
.Font.ColorIndex = wdRed
.Font.Bold = True
.TypeText "REJECTED"
End With
End If
End Sub

Generate bookmarks in Word 2010 programmatically, with the header name as the bookmark name

I need to generate bookmarks in Word 2010 programmatically, with the header name as the bookmark name.
I have the following code which makes a word a bookmark, but the bookmark name remains the same as the string Heading 1 is only available in the name variable:
Sub bookmarking()
Selection.EndKey Unit:=wdLine, Extend:=wdExtend
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:=" Heading 1"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
End Sub
Instead of the Heading 1 in the name variable, I want content from the clipboard. Please help me replace that Heading 1 with clipboard content.
Use a DataObject from the Microsoft Forms 2.0 Object Library:
Private Function GetClipboardData()
Dim objDataObject As MSForms.DataObject ''need to add reference in Tools |References
Set objDataObject = New MSForms.DataObject
objDataObject.GetFromClipboard
On Error Resume Next
GetClipboardData = objDataObject.GetText
If Err.Number = -2147221404 Then
MsgBox "Error: current clipboard data is either empty or is not text. Clibpoard must contain text."
End If
End Function
Then, back your main code, have the bookmark name be this clipboard data:
...
.Add Range:=Selection.Range, Name:=GetClipboardData()
...
Is this a good start for you? There are other ways which may be more robust depending on your needs. However this should serve as good proof-of-concept.

How to set Selection.Start in VBA?

I have a problem with adjusting selection inside of a table. I have a function that goes through a document word by word to analyze it's contents looking for specific patterns. Unfortunately, in tables Char(7) character breaks the selection - when it's selected, all cells become selected automatically. To work around this problem I store the proper Selection.Start parameter.
Here is my code:
If InStr(Selection.text, Char(7)) > 0 Then
Selection.start = selStart
Selection.End = selStart + (Len(tekst) - 2)
End If
Well, it did not help. I can see, while debugging, that selStart is 441 and Selection.Range.Start is 427 (427 would be the beginning of the cell, when the word I'm looking for is on the position of 441). In the next step... Selection.Start still is 427.
I've also tried another aproach using MoveStart and MoveEnd but no matter what I do, the Selection.Start doesn't change.
Well of course!
I can't move Selection.Start, while Chr(7) is in the selection! Everything works perfectly when I move Selection.End fisrt...
If InStr(Selection.text, Chr(7)) > 0 Then
Selection.MoveEnd Unit:=wdCharacter, Count:=-1
Selection.start = selStart
End If
Maybe a different approach is in order: rather than manipulate the selection, iterate the Document.Words collection. Something like:
Sub PreccessAllWords()
Dim doc As Document
Dim wd As Range
Set doc = ActiveDocument
For Each wd In doc.Words
If wd.Text = "Foo " Then
wd.Text = "Bar "
End If
Next wd
End Sub

Copy charts from excel to word - indeterministic behaviour

I am currently copying a lot of diagrams from excel to word via macro. I used the Record Macro functionality which helped me to produce the following code:
Set charts = Sheets("Charts").ChartObjects
For Each chart In charts
WordApplication.Selection.TypeParagraph
WordApplication.ActiveDocument.Tables.Add Range:=WordApplication.Selection.Range, NumRows:=2, NumColumns:= _
1, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:= _
wdAutoFitFixed
With WordApplication.Selection.Tables(1)
If .Style <> "Table Grid" Then
.Style = "Table Grid"
End If
.ApplyStyleHeadingRows = True
.ApplyStyleLastRow = False
.ApplyStyleFirstColumn = True
.ApplyStyleLastColumn = False
.ApplyStyleRowBands = True
.ApplyStyleColumnBands = False
End With
WordApplication.Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter
chart.Copy
WordApplication.Selection.Paste
WordApplication.Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend
' configure the shape (resizing)
WordApplication.Selection.MoveDown Unit:=wdLine, Count:=2
Next
So what I do is, put a Return, add a table with 2 rows and align the first row to Center. Then add the chart by copying it from Excel and pasting it into Word. Do some tinkering with the shape (removed) by selecting it (via the MoveLeft command) and finally, move 2 steps down (to leave the table) and redo for all the charts.
If I step through this with F8 I get the result I want. However, if I just let it run I see different result all the time, for instance:
The selection stays in the table even after the MoveDown command
The shape is still selected after the MoveDown command
run-time error '4605': This method or property is not available because the object refers to the end of a table row (due to the selection not being moved and the Tables.Add is done inside the previous table
correct result
My question:
How can I make it work without having to step through the macro manually?
Using Windows XP, Excel 2007 (12.0.65.62.5003). Note that the issue does not behave the same on Windows 7 (not tested on Windows Vista).
It seems the last line didn't always leave the table that I inserted. I replaced the following line:
WordApplication.Selection.MoveDown Unit:=wdLine, Count:=2
with this
Do Until Not WordApplication.Selection.Information(wdWithInTable)
WordApplication.Selection.MoveRight Unit:=wdCharacter, Count:=1
Loop
And now it works as it should