house flower tree box candy bug book
cheese rat dog bird mouse flea
leaf grass skunk telephone computer blue
etc., etc.
What I want to do is have a macro take the last word in
each row and put them in one column, as follows:
book (from top row, last word)
bug
candy
box
tree
flower
house
flea (from second row, last word)
mouse, etc., etc.
Hi Rebecca,
Not too easy...
If you don't need to keep any formatting, the best (= fastest) way would be
to use string functions like Left, Mid, Instr, Split, Join.
But those are a bit difficult if you have never used any of them.
And it wouldn't have much to do with Word, apart from the start where you
would read the text into a string and delete it, and the end where you
would insert the end result into Word again.
The next best thing would be to use a Range, and move that around to access
different parts of the text, and move them. But this also is a bit
difficult, because you can't easily see what is happening.
So let's do it with the Selection.
Let us start by arranging the document and the VBA editor next to each
other.
Create an empty macro in the editor, and give it a name that describes what
you try to do.
I used
Sub ParagraphsSplitWordsBackwards()
End Sub
But if you can think of a better name, use that!
Put your cursor in the first paragraph in the document.
Let's first try to select the whole paragraph.
You can do that with
Selection.Paragraphs(1).Range.Select
in the macro.
Type that into the macro, and run the macro (F5, or single-step through the
code with the F8 key).
If the Selection would span several paragraphs, Selection.Paragraphs(1)
would be the first Paragraph in the Selection, Selection.Paragraphs(2) the
second, and so on.
If the Selection is inside a paragraph, Selection.Paragraphs(1) gives you
this paragraph. That takes a bit of getting used to, but is very useful.
Now if we want to select that paragraph,
Selection.Paragraphs(1).Select
might seem logical, but after you type
Selection.Paragraphs(1).
"Select" isn't offered. (I assume you have checked all the help you can get
in the VBA editor's "Tools > Options > Editor"?)
But just about every object in Word has a Range, which can be selected, so
we use the roundabout way of first getting the Range of the paragraph.
Selection.Paragraphs(1).Range.Select
Now let's try to get the last Word in the Selection.
Selection.Words.Last.Select
You may be in for a surprise here: The final paragraph mark gets selected.
Word treats a paragraph mark (and punctuation like "." or ",") as separate
words.
We can try to select the last word with
Selection.MoveStart Unit:=wdWord, Count:=-1
You notice the yellow arrow to the left of the code if you use F8 to
single-step through the macro?
You can drag that arrow to any line in the code with the mouse, and that
line gets executed next with F8 (single step).
Also you can type new lines into your macro, and drag the yellow arrow to
them.
In the document window, you can use Ctrl+Z (Undo) to undo any changes if
the macro didn't work as you expected.
Now we want to move the selected last Word into an extra paragraph above
the paragraph with all the rest of the words.
Let's first insert a paragraph mark in front of the word:
Selection.InsertBefore vbCr
Now the word is in a paragraph by itself, but below. And the paragraph mark
above is still selected.
First, deselect that pagaraph mark:
Selection.MoveStart Unit:=wdCharacter, Count:=1
The paragraph with the single word is now selected.
One way to move it up would be to cut it to the clipboard, move the
Selection up, and paste it again.
A way that needs only one line of code is
Selection.Range.Relocate wdRelocateUp
I use this all the time from the user interface (Alt+Shift+Up,
Alt+Shift+Down) to move one or several paragraphs or table rows up or down.
If you know such tricks from the user interface, you can use the macro
recorder to give you the code.
Now we have moved the last word up above the original paragraph.
But it's still selected. To re-select the original paragraph, let's use
Selection.Next(Unit:=wdParagraph, Count:=1).Select
(You can also try some other ways to select it. With two or more lines of
code, there are lots of possibilities. You can experiment with all the
methods you get offered after you type "Selection" followed by a ".")
The code up to now is
Selection.Paragraphs(1).Range.Select
Selection.Words.Last.Select
Selection.MoveStart Unit:=wdWord, Count:=-1
Selection.InsertBefore vbCr
Selection.MoveStart Unit:=wdCharacter, Count:=1
Selection.Range.Relocate wdRelocateUp
Selection.Next(Unit:=wdParagraph, Count:=1).Select
We need to repeat this for the rest of the words. We should stop if there
are only 2 words left (one real word, and the paragraph mark):
Selection.Paragraphs(1).Range.Select
Do While Selection.Words.Count > 2
Selection.Words.Last.Select
Selection.MoveStart Unit:=wdWord, Count:=-1
Selection.InsertBefore vbCr
Selection.MoveStart Unit:=wdCharacter, Count:=1
Selection.Range.Relocate wdRelocateUp
Selection.Next(Unit:=wdParagraph, Count:=1).Select
Loop
Putting the condition at the top of the loop makes sure that the loop
doesn't get executed at all if it is not necessary.
I left the first line (which originally selected the paragraph) outside the
loop, because the paragraph already is selected.
After all the words in the first paragraph have been processed, we need to
move the Selection down a paragraph again:
Selection.Next(Unit:=wdParagraph, Count:=1).Select
and start over with the next paragraph.
We need to do this in a loop until the next paragraph is empty or contains
only one word, at which point the macro is done:
Sub ParagraphsSplitWordsBackwards()
Selection.Paragraphs(1).Range.Select
Do
Do While Selection.Words.Count > 2
Selection.Words.Last.Select
Selection.MoveStart Unit:=wdWord, Count:=-1
Selection.InsertBefore vbCr
Selection.MoveStart Unit:=wdCharacter, Count:=1
Selection.Range.Relocate wdRelocateUp
Selection.Next(Unit:=wdParagraph, Count:=1).Select
Loop
Selection.Next(Unit:=wdParagraph, Count:=1).Select
Loop Until Selection.Words.Count <= 2
End Sub
This time we put the condition at the end, since we want to run the inner
loop at least once.
If the word count is 2 or less, nothing bad will happen because of the
condition in the inner loop.
If you got lost somewhere, just put your cursor in the finished macro, and
use F8 to single-step through the code, then watch what every line of code
does.
You can try some different methods (there are lots of possibilities to move
the Selection), or you could try to work with a Range:
Dim myRange as Range
Set myRange = Selection.Paragraphs(1).Range
Ranges don't have as many methods for movement, so you'd have to rewrite
the code quite a bit.
To watch were myRange is at any given time, you can use
myRange.Select
in your code (or in the "immediate window").
Instead of .Relocate, you could try .Cut and .Paste, or use .FormattedText
to duplicate the Range where you want to move it, and .Delete the old
Range.
Or you could try some totally different approach: For example replace all
spaces in a paragraph with ^p paragraph marks. The words are now in
paragraphs by themselves, but in the wrong order. Put them in a one-column
table, put numbers 1, 2, 3 ... in a second column, sort the table so the
numbers are descending, remove the numbered column, and convert the table
back to text.
Hope this has given you some ideas,
Klaus