Heading

This is some text inside of a div block.
This is some text inside of a div block.
This is some text inside of a div block.
min read

Move a sentence using the clipboard

Word • Macros • Editing
Peter Ronhovde
22
min read

We create a pair of macros to quickly move a sentence forward or backward in a document using the clipboard. The macros can also be easily extended to move words.

Thanks for your interest

This content is part of a paid plan.

Move a sentence in a document

Moving a sentence left or right in the document seems like a simple task, but it's slower than it feels with manual editing. In the vein of streamlining common editing tasks, we turn it into a keystroke.

Example macro moving a sentence left in a paragraph
Example macro moving a sentence left in a paragraph

Feel like you don’t do that often?

This is one of those subtle tasks we just do and don't realize how often, but the faster it's done the quicker we get to move on with other editing. It doesn't feel like we would need it automated, but I use it often. I suspect you'll be pleasantly surprised at how useful it is.

With a caveat

The final macros below work well, but they're not the full recommended solutions since they use the clipboard for a task not specifically related to the clipboard—

Huh?

Why talk about then?

Automatically moving a sentence using VBA is one of those jobs that sounds easier than it is. The macros below are a direct way to accomplish the task that mimics a manual solution. On the plus side, they are relatively simple to implement while still achieving 95.432% of what we want to accomplish, and they preserve the character formatting of the moved text. On the negative side, they're a compromise solution using the clipboard. The member versions do a better job and include extra features, but they are more complex.

Create the empty macro

A previous post covers creating an empty macro like the one shown below. When you’re done, you’ll have something like:

Sub MoveSentenceLeft()
' Move the current sentence before the previous sentence

End Sub
Sub MoveSentenceRight()
' Move the current sentence after the next sentence

End Sub

The single quote tells VBA the rest of the text on that line is a comment meant for human readers. We start our macro steps on the empty line.

What are the manual steps?

What steps would we use to manually move the current sentence?

  • Use the keyboard or mouse to select the current sentence (either way is slow)
  • Press Command+X in Word for Mac (or Control+X in Windows) to cut the sentence to the clipboard
  • Move left one sentence
  • Paste the sentence back into the document at the new location

Anytime we find a common sequence of steps that are performed nearly the same way every time, it's a good candidate to consider for a macro.

The speed of the sentence movement and selection can be improved if we add shortcuts to several standard Word sentence commands (or a specific member macro). Even with improved sentence manipulation, it's still four steps we can replace with one keystroke.

VBA techniques often differ from manual steps

This macro emulates the above steps somewhat closely, but we often don’t perform the steps in VBA exactly like we would do them in Word.

Don't use the clipboard unless necessary

This implementation of the move sentences macros uses the clipboard, but generally speaking, don't use the clipboard unless it's related to the purpose of the macro. Using the clipboard is natural in the manual steps.

VBA offers a better approach, but the full implementation is much more complicated than the final macros below, so it's relegated to a member version. It accounts for dialog or parenthetical text and handles most gotchas automatically.

Why avoid using the clipboard in a macro?

The clipboard contents shouldn't mysteriously change in the background while we work. Suppose we're cutting and pasting content around a scene in our manuscript, and we happen to move a sentence in a paragraph using one of these macros. Then we go somewhere else in the scene and attempt to paste the other cut content, but … it's the sentence we moved?!

Huh?

The clipboard should only change when the writer expects it to change. For example, a tentative CopyCurrentSentence macro obviously needs the clipboard based on its name, but a MoveSentenceLeft macro does not imply it uses the clipboard. If the clipboard were the only way … maybe we'd be content, but VBA gives us better tools to accomplish the task once we understand it better.

Move a sentence backward

We'll first implement a macro to move a sentence backward in the document. Then we'll adapt it to move in the other direction.

Expand the Selection over the sentence

We need to select the current sentence, so we can cut it later. The Expand method works perfectly for this subtask.

Selection.Expand ' Not done ...

The Expand method is a simple one-line command to make a specific selection, but more importantly, it will not grow the Selection beyond the given document unit.

Available expansion units include the obvious ones like words, sentences, paragraphs, etc. Each constant is preceded with a “wd” to identify it as a standard Word constant followed by an obvious unit name. The default is by a word, but we need a sentence.

Selection.Expand Unit:=wdSentence

We assign the wdSentence constant to the option name, which is Unit here, using a colon equals := symbol.

Cut the Selection

Now, we cut the selected sentence using the aptly named Cut method.

Selection.Cut

This also collapses the current Selection in the document to an insertion point.

Move to the previous sentence

In preparation to paste the cut sentence, the MoveLeft method jumps to a previous document unit.

Selection.MoveLeft ' Not done ...

The default movement unit is a character, so we need to specify a sentence unit like we did with the Expand method earlier.

' Move backward in the document one sentence
Selection.MoveLeft Unit:=wdSentence

We omitted Count option since it defaults to one unit.

Paste the sentence

Paste the sentence in the new location using the obvious Paste method.

Selection.Paste

The Cut and Paste operations preserve any text formatting.

Select the moved sentence (optional)

I prefer to end the macro with the pasted content selected as a visual indicator of the change. After the paste action, the insertion point is placed immediately after the pasted content, so we want to select the previous sentence.

We first move Selection inside the sentence text using the MoveLeft method.

Selection.MoveLeft ' Position Selection inside moved sentence

The default move is a single character which works in this case, so we omit any options. This move automatically collapses the Selection which helps avoid any logical issues later (see gotchas below) with the Selection spanning a sentence boundary.

Once the Selection is inside the moved sentence, we expand over it as we did at the beginning of the macro.

Selection.Expand Unit:=wdSentence ' Select the moved sentence

Alternative selection approach misses special cases (aside)

A fancier VBA-like approach would directly reference the previous sentence before selecting it. Without a lot of explanation, the command would use the Previous method something like:

' Alternative moved sentence selection (not used)
Selection.Previous(Unit:=wdSentence).Select

This also selects the moved sentence range, and I would prefer the approach, but it misses two special cases. Rather than include another conditional statement to catch them, it's easier to use the more manual selection steps above since it works for every case in this macro.

Move the sentence right

What changes when moving the sentence right in the document?

Instead of moving left in the document to paste the sentence, we use the MoveRight method.

Selection.MoveRight Unit:=wdSentence ' Move forward to paste the sentence

Oddly, that's the only change, but don't let the simplicity fool you. A lot of testing went into making sure it works for multiple regular and special cases.

Gotchas

What could go wrong in the macro? Or what might annoy us enough to go through the effort to fix it?

Correcting the gotchas mentioned below might feel more like stomping roaches when a decrepit box is overturned, but we squash most of them below. A few are deferred to the member article for brevity or due to complexity.

Unfortunately, the special cases sometimes make the macro look more like programming than editing automation, so skip to the final macros below if you don't want the details.

Watch out for deleted text

Anytime we cut or delete content, we should think harder about potential problems. Fortunately in these macros, we paste the text back into the document, so we probably won't lose any content.

What if an initial selection exists?

A typical gotcha consideration for most editing macros is whether an initial selection exists or not. If so, what do we do with it?

If a selection spans only part of a sentence, it has no effect because an early step is to expand over the whole sentence.

What if multiple selected sentences are selected?

A subset gotcha relates to how much content is selected. If the initial selection spans a sentence boundary, it could cause some logical problems with the expected behavior. The initial Expand command would expand to the nearest sentence both forward and backward in the document. Multiple sentences would be selected.

While this is not a deal breaker, it may not be what some writers expect. Unintuitive macros are bad even when you write them for yourself. Nine months down the road, you’ll inevitably forget that special conditions allows in the macro. In this macro, I actually think it fits well with the typical behavior, but we add a step to avoid the issue for extra clarity.

Collapse the Selection

How do we solve this issue?

We can just collapse the Selection first using its Collapse method.

Selection.Collapse

The default is to collapse toward the beginning of any initial selection. The Collapse method does not affect an insertion point since it is already collapsed. Thus after this step, we know no document content is selected, so our macro has a clear starting point.

This is a relatively common first step to avoid any issues with an initial selection. Any time we're unsure about how a starting selection will affect our macro, and it isn’t necessary for the macro to work properly (like adding contextual novel notes), it’s not a bad idea to just collapse the Selection (or Range) as an early step in the macro.

Paragraph mark issues with the last sentence

I usually leave such corrections out of the public version since it complicates the macro, but it is jarring to have a paragraph split when you just want to move a sentence in the document. A typical writer would definitely not expect a paragraph mark to move with a cut sentence. A paragraph mark is more intuitively associated with the paragraph not its last sentence.

What’s the problem?

If we Expand the selection over the last sentence of a paragraph, it automatically includes the paragraph mark. This is the default Word behavior, so it's not a mistake. It is, however, unintuitive since an expansion over an interior sentence does not behave the same way.

What happens?

When we cut the sentence and and paste it into the new location, the paragraph mark comes with it which splits the paragraph.

Arghhh.

What do we do about it?

We need to exclude the paragraph mark if our macro is going to work intuitively and move only the sentence text.

How?

We check whether the last character is a paragraph mark and remove it from the Selection if so.

Get the last character

In this gotcha scenario, the last character of the last sentence selection might be the paragraph mark, so we need to determine what the last character is. We start by using the Characters collection of the Selection.

Selection.Characters ' Not done ...

To get the last character of the collection, we refer to its Last property.

Selection.Characters.Last ' Still not done ...

We need the text of the last character for the paragraph mark comparison below. The last character is a Range, so we use its Text property.

' Last plain text character of the current Selection
Selection.Characters.Last.Text

This command uses with the current Selection even as modified within the macro.

Character comparison

In Word VBA, the paragraph mark is a special character named vbCr from a miscellaneous constants table. We need to compare the last character to a paragraph mark character to determine if we've selected the last sentence of the paragraph. A rough conditional statement is:

If last character of the Selection is a paragraph mark then
' Remove the paragraph mark from the Selection ...
End the paragraph mark check

See our brief introduction to conditional statements in VBA for more explanation.

Typical VBA condition with values (aside)

A comparison of values in VBA looks like:

ThisValue = ThatValue ' Typical value comparison

This looks like an assignment storing ThatValue in the ThisValue variable, but when it's used in a conditional statement, VBA interprets it as a True or False (Boolean) value.

Condition for a paragraph mark

We compare the last character to a paragraph mark character.

' Condition to detect a selection that ends with a paragraph mark
Selection.Characters.Last.Text = vbCr

When used in a conditional statement, this condition will be True if that last character is a paragraph mark and False if not. Text comparisons in VBA must match exactly, but we're only comparing individual (usually non-alphabetic) characters, so the distinction in not important here.

Remove the paragraph mark character from the Selection

How do we remove a paragraph mark from the end of the Selection?

A paragraph mark a literally a single special character at the end of the paragraph, so we just move the End position of the Selection backward by one character. The relevant command is the MoveEnd method.

Selection.MoveEnd ' Not done ...

The default unit is by a character, which is what we want, so we can omit the Unit option. The Count option tells the method how many units to move. Negative values correspond to backward in the document. We need one unit backward, so we use -1.

Selection.MoveEnd Count:=-1 ' Move End backward by one character

The command is only run if we find a paragraph mark at the end, so it should go inside the above conditional statement.

Remove the paragraph mark conditional statement

The conditional statement to remove the paragraph mark if it exists at the end of the Selection is:

If Selection.Characters.Last.Text = vbCr Then
Selection.MoveEnd Count:=-1 ' Remove ending paragraph mark
End If

The If statement does nothing if the last character is anything other than a paragraph mark. I prefer to condense conditional statements containing only one command onto a single line, but this one is a little long to read well (word wrap is icky with code).

Could we do better?

Technically, the expanded Selection for the last sentence would also include any empty paragraphs after the sentence (not sure why this is the default behavior). The above is a direct and logical solution, but the member version further corrects for this unusual case using the MoveEndWhile method.

Missing space between sentences

When moving the last sentence of the paragraph, the pasted sentence will most likely not have an ending space because the last sentence does not usually end with one like other sentences in a paragraph. We need to ensure a space is included with our moved sentence. The catch is we don't want to add a space every time since it will already be present at the end of most copied sentences.

Next character with an insertion point

We again need an If statement, but here we want to know whether the previous character is a space.

Why check the previous character?

The Paste methods pastes the text and positions the insertion point at the end of the pasted content. If a space is present, it will be just to the left of the current insertion point position. We need to check it.

Get the previous character

We can get the previous character relative to the Selection using the Previous method.

Selection.Previous ' Not done ...

The default unit is a character, so we can omit the Unit option. We also omit the Count option because we want the first previous character.

This method will give us the Range of the previous character, but we need to compare it to a space character, so we want the actual text. As before, we use the Text property.

Selection.Previous.Text ' Character text just before the Selection

Character comparison

Our comparison is whether the First character is not equal to a space.

Selection.Characters.First.Text <> " "

In VBA, the "not equal to" <> symbol represents "less than or greater than" the value on the right much like >= represents greater than or equal to a value. Text comparisons in programming languages often mimic mathematical symbols, but the specifics vary. For example, text comparisons must match exactly to be equal. We're only comparing a single character, so any character other than a space " " is not equal to a space.

What do we do?

Since any pair of English sentences needs a space between them, we insert a space if it is not present. The relevant method is InsertAfter.

Selection.InsertAfter ' Not done ...

We need to specify what text to insert, so we assign a literal space " " in double quotes to the Text option.

Selection.InsertAfter Text:=" "

Technically, one only option is allowed with this method, so we could omit Text:= and just put the space " ", but this is clearer.

Conditional statement to insert the space

Putting the condition and the corrections together, the short conditional statement to correct for a missing space between sentences is:

If Selection.Previous.Text <> " " Then
' No space, so add one between the sentences
Selection.InsertAfter Text:=" "
End If

When we have a single command inside an If statement, so we can condense it into one line.

' Ensure a space separates the sentences
If Selection.Previous.Text <> " " Then Selection.InsertAfter Text:=" "

It's a little long, but it's (just barely) clearer.

Extra space at the end of the paragraph

When moving the first sentence of one paragraph to the the last sentence of the previous paragraph, the sentence text will probably include a space at the end. We don't want a space hiding at the end of our paragraphs.

Straggling spaces are annoying, but the macro is already getting long, and it doesn’t cause a substantive problem. Since this little issue pops up several times over multiple macros, we address it in a separate function to delete spaces at the end of a paragraph, but we'll save the correction for the member macros.

What about an empty paragraph?

If the paragraph is empty, the macro will still try to move the non-existent sentence. This will probably copy and paste nothing. At worst, it may result in an unsightly edit for an unusual gotcha, so we'll defer catching it to the member article. If you're interested, another function checks for empty paragraphs which can be used to quit the macro if it starts in an empty paragraph.

What about a single sentence paragraph?

What happens if we move the last sentence of a paragraph?

The sentence moves as normal, but the macro leaves an empty paragraph. We'll defer this correction to the member article, but if you're interested, check out another function to delete an empty paragraph.

Final sentence movement macros

Both final macros include some of the gotcha corrections mentioned above.

Move sentence backward macro

The final macro to move the current sentence backward in the document is:

Sub MoveSentenceLeft()
' Move the current sentence one sentence left in the document
' Avoid any gotchas with a starting selection
Selection.Collapse

' Select the current sentence
Selection.Expand Unit:=wdSentence
' Check for the last sentence of the paragraph
If Selection.Characters.Last.Text = vbCr Then
Selection.MoveEnd Count:=-1 ' Remove the paragraph mark
End If

' Move the sentence backward one sentence
Selection.Cut
Selection.MoveLeft Unit:=wdSentence
Selection.Paste

' Ensure a space separates the sentences
If Selection.Previous.Text <> " " Then Selection.InsertAfter Text:=" "

' End the macro with the moved sentence selected (optional)
Selection.MoveLeft ' Move back to the pasted sentence
Selection.Expand Unit:=wdSentence
End Sub

Move sentence forward macro

The move right version is almost identical only changing one move command.

Sub MoveSentenceRight()
' Move the current sentence one sentence right in the document
' Avoid any gotchas with a starting selection
Selection.Collapse

' Select the current sentence
Selection.Expand Unit:=wdSentence
' Check for the last sentence of the paragraph
If Selection.Characters.Last.Text = vbCr Then
Selection.MoveEnd Count:=-1 ' Remove the paragraph mark
End If

' Move the sentence forward one sentence
Selection.Cut
Selection.MoveRight Unit:=wdSentence
Selection.Paste

' Ensure a space separates the sentences
If Selection.Previous.Text <> " " Then Selection.InsertAfter Text:=" "

' End the macro with the moved sentence selected (optional)
Selection.MoveLeft ' Move back to the pasted sentence
Selection.Expand Unit:=wdSentence
End Sub

We need a separate macro to move forward in the document since Word doesn’t allow parameters (in the parentheses) when assigning macros to shortcuts.

I assigned my versions to Option+Shift+Left or Right arrow in Word for Mac or Alt+Shift+Left or Right on Windows. These shortcuts aren't perfect since I would prefer they extend a selection by a sentence instead, but they're the best solution for me so far since I move sentences more than I need to select them.

What did we accomplish?

We have two macros to quickly move sentences forward or backward with a keystroke while preserving character formatting. The latter is an important stipulation since it isn't as easy as it sounds. For example, we would not want our inner dialog, often represented as italics, to revert to regular text.

Not as easy as it seems

The trivial similarity between these macros is a little deceptive. While they only differ by one command, it's actually a coincidence combined with some careful testing to ensure the steps handle the multiple regular and special cases without any issues. In these macros, it resulted in an unusual single step difference.

The macros also partially rely on Word's automatic spacing corrections to function properly for beginning or end of paragraph sentences. I usually prefer my macros don't rely on Word's automatic "help" to work as intended, but allowing it is reasonable compromise for a public version of the macro.

Improvements

What could we do better? The big brother member version uses a better VBA-like approach to implement most of these suggestions.

Uses the clipboard … bleh

My main complaint about this macro is it uses the clipboard. Leaning on the clipboard is an obvious, but naive, approach since it changes the clipboard in the background.

Spacing and empty paragraph tweaks

Both macros above leave straggling spaces at the end of a paragraph, and they leave an empty paragraph if the paragraph only included the moved sentence.

Ughhh.

For more complete versions, I would add some steps to delete any straggling end of paragraph spaces and remove an empty paragraph if we move the last sentence in it. These adjustments are omitted above in the interest of keeping the macros simpler for presentation purposes.

What about dialog or parentheses?

As writers, it is convenient (maybe essential?) if our most used macros understand dialog. A full featured version of these macros would know whether to move the sentence within dialog or move the whole sentence if it is all dialog. A similar idea applies to parentheses.

Undo record

I might add an undo record, so the multiple changes are all undone as a single step. This addition makes the macro feel more professional, but it must be implemented properly, or it could cause significant problems with undo actions. In the worst case, it can temporarily mess up cloud syncing.

Use functions?

The two macros include several common steps.

  • Both select the current sentence while excluding a possible paragraph mark
  • Both check and correct for proper sentence spacing after pasting the text

Both sets of steps are necessary in both macros, and they're identical. When we encounter a common sequence of steps, they are a good candidate to extract into a separate function. With functions handling the subtask details, the main macro often reads and feels simpler. Moreover, if we need that task in another macro, we just use the function again which saves us work.

We've already implemented a sentence selection function, and an upcoming member function may include a macro to check and correct word or sentence spacing.

Two steps at the end of the macros select the pasted sentence, but these are an exception. While they're also identical steps in the macros, they're a minor task specifically related to the sentence position relative to the Selection when the text was pasted into the document.

The downside of implementing functions is it feels a lot more like programming than creating writing and editing macros.

Adapting for Words

The above macros can be easily adapted to move a word—

What?

Yeah, words. We use them all the time, but hold on before you get uptight about obsessively specific macros.

Just start writing or editing in your current manuscript. I suspect you’ll find yourself occasionally wanting to move individual words left or right. With these little word tweezers in your toolbox there's no click and drag or cut and paste. Just done.

Plus, the extra macros fit nicely with our existing editing toolset. It’s a trivial amount of work to extend the above sentence macros.

  • Change the wdSentence unit constants on the Expand, MoveLeft, or MoveRight methods to the word unit constant wdWord.
  • Remove the conditional statement to check whether the expanded selection includes the end of paragraph mark since this cannot happen when expanding by a word.

The step to validate a space separating the two words is still necessary. I would probably add some logic to handle beginning of sentence capitalization, but the final move word macros are left as an exercise for the reader.

Affiliate Links

If you're interested in using Word or another tool related to the article, check out these affiliate links. I may make a small commission if you purchase when using them, but there is no increase in cost for you, and it helps to support this site and associated content.

I've been using Microsoft for Business for commercial use (that's us writers) on one of the lower pricing tiers for years. I get to use my macros, have online storage, and don't have to worry about software updates.