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

New paragraph with sentence improved

Word • Macros • Editing
Peter Ronhovde
26
min read

Some simple editing tweaks are surprisingly useful. We create a macro to insert a new paragraph with the current sentence without disturbing the edit location. The revised solution also adds some spacing corrections and introduces us to thinking a little more like VBA when writing new macros.

Thanks for your interest

This content is part of a paid plan.

Create a new paragraph with a sentence

Inserting a new paragraph with the current sentence sounds almost pointless at first … until you get used to using it. I created this macro on a whim, but now it's one of my favorites.

Example of macro to create a new paragraph with the current sentence
Example use of a macro to create a new paragraph with the current sentence

It's like getting a gift you didn't know you wanted. Just try it.

Create the empty macro

We're starting from scratch, so open the VBA editor (Option+F11 on Mac or Alt+F11 on Windows) and create the following macro skeleton. If you prefer, a previous post covers creating an empty macro via the menu interface.

Sub NewParagraphWithSentence()
' Insert a new paragraph with the current sentence

End Sub

The single quote tells VBA the rest of the text on that line is a comment meant only for human readers. It's a good practice to add a longer comment at the top describing the main purpose of the macro beyond what the name implies. I usually further include any special points or restrictions that may not be obvious. We begin our macro steps on the empty line.

What are the manual steps?

If we were to manually insert a new paragraph that begins with the current sentence, what steps would it require?

  1. Move the insertion point to the beginning of the sentence.
  2. Delete the extra space between the sentences.
  3. Press the Return key to create the new paragraph.
  4. (Maybe also) Jump back to your previous edit location to keep working?

No standard shortcut exists for Step 1, but we have an article on how to add one to Word using some standard (almost hidden) Word commands. Steps 2 and 3 just require tapping the respective key, so no problems for either of them. In VBA, both are single-line commands. One might argue a step 4 exists to return to your original edit location to continue working.

It’s just three (or four) steps but saving two or more steps every time adds up over the course of a novel. Plus, it’s just nice not to have to do them. One tap. Poof … it's done, and you keep writing.

Manual techniques are usually less efficient

Emulating the exact manual steps is often not the best way to write a macro in VBA. We based the simpler version on it in part because it is logically easy to implement when you're new to Word macros, but we can often work out a smarter VBA way. The final version below is more elegant (if you can call a macro that) and a tad more functional than the previous version.

Let's leverage some of VBAs methods to rework our macro. For simplicity, we'll mostly assume we are working with an insertion point since an initial selection will not change the result of this macro as its written.

Setup working ranges

We will define three working ranges in the document: one for the initial sentence that contains the insertion point or selection, a second for the initial paragraph, and a third just to provide some added clarity when we attempt to delete the space between the sentences.

Dim rSentence As Range, rParagraph As Range, r As Range

Dim declares the variables as usual. Declaring variables is technically optional in VBA, but I recommend it for clarity. A common naming system indicates the type of variable at the beginning the name. I usually begin range variable names with an "r" to remind myself what it stores. VBA does not care as long as we do not try to use one of its reserved keywords (like End or Sub).

We can specify multiple range variables on the same line by separating them with a comma, but each variable needs a type "As Range" (or whatever), or the implicit type will be a Variant (a generic variable type). Sounds like a science fiction movie. Watch out for Deckard …

What is a range?

Let's briefly go over what a Range (capital R) is in Word VBA (see also our introduction to ranges). A Range is the name of a VBA "object" type that tracks a literal range of document content, but it further contains other information or settings (properties) and actions (methods) that allow us to control them and the corresponding document content. Essentially, a range is defined by Start and End positions in the document which are stored literally as a character count from the beginning of the document. Ranges have a lot in common with the Selection, so if you've been following along with previous articles, you'll see many of the same or similar property and method names.

Working sentence range

The initial sentence range can be identified using the Sentences collection of the Selection.

Selection.Sentences ' Not done ...

We need the first sentence range, so we use the First property of the collection.

Selection.Sentences.First

VBA does not have a "Sentence" object (as in capital S) like it does for a Paragraph (capital P), so the First sentence reference returns the document range (contrast with the Paragraphs collection below). Using the First property like this also allows us to ignore whether an initial selection existed or not. Regardless of how large the initial selection is, we only work with the first sentence.

We assign this sentence range to our rSentence range variable.

Set rSentence = Selection.Sentences.First

VBA requires the extra keyword Set since a Range is a VBA object not just a value. We can now conveniently refer to the initial sentence range as rSentence.

Working paragraph range

We also want the initial paragraph range, but this is more for tidiness, so the macro reads well. Similar to above, we start with the Paragraphs collection of the Selection.

Selection.Paragraphs ' Not done ...

We get the first paragraph using the First property. Similar to the first sentence range above, this allows us to ignore any initial selection.

Selection.Paragraphs.First ' Still not done ...

Unlike the Sentences collection, a Paragraph reference like First returns an actual Paragraph (capital P) object corresponding to a specific paragraph in the document. Of course, a Paragraph is kind of like a document range in that it spans a specific region of document content, but a Paragraph in VBA also has its own properties and methods. As such, we need to refer to the paragraph's range before we can store it in a range variable. We use its Range property.

Selection.Paragraphs.First.Range

We're finally ready to assign the initial paragraph range to our rParagraph range variable.

Set rParagraph = Selection.Paragraphs.First.Range

Now we can specifically refer to the initial paragraph range using rParagraph (if a selection exists, it will be the first paragraph of that selection, but this possibility will not change the overall result).

Working range (other)

We add a third working range for convenience just called r for simplicity. In my own macros, I would probably reuse one of the above range variables, but for presentation purposes, I wanted to maximize the clarity of the later steps where we delete the space(s) between the sentences.

We cannot use the variable r until it is assigned a valid document range later (technically, it currently has a value of Nothing), but we assign it a meaningful range below just before we use it.

Avoid the first sentence of the paragraph

We may not want to insert a new paragraph if the initial insertion point begins in the first sentence.

Why?

The new paragraph will be empty which is a little odd in the context of the macro. It's not wrong per se. It's more of a preference, but I find it a little awkward. Another macro does just this task where the behavior is expected and not a side effect.

Detect the first sentence

Creating a new paragraph with the first sentence is more of a logical issue since it would insert an empty paragraph. It's okay but not fully consistent with the idea of the macro. A rough conditional statement to check would look something like:

If sentence is first in the paragraph Then
' No new paragraph needed, so just exit the macro
End the conditional statement

So how do we detect the first sentence of the paragraph?

First sentence of paragraph condition

We already have two ranges defined above, so we only need to check whether they start at the same document location. The Start position of a Range variable is a literal character position relative to the beginning of the document. With this in mind, we can just check whether the respective Start positions have the same value.

' Do the sentence and paragraph start at the same document location?
rSentence.Start = rParagraph.Start

When used in a conditional statement, VBA interprets this as a True or False (Boolean) value answering the question. Inserting it into our conditional statement, we have:

If rSentence.Start = rParagraph.Start Then
' No new paragraph needed, so just exit the macro
End If

If you would like to brush up, see our brief review of conditional statements in VBA.

How do we exit the macro?

What do we do if so? We just to exit the macro. It's super simple.

Exit Sub
First paragraph test

Putting them together, our test is:

If rSentence.Start = rParagraph.Start Then
' No new paragraph needed, so just exit the macro
Exit Sub
End If

This immediately exits the macro not running any other steps below the line. The range variables created above will just disappear into ones and zeros (and probably a teensy weensy bit of heat) somewhere inside the computer.

Shorter conditional statement (optional)

This command is short enough that we can condense it onto one line.

' Check for the first sentence of the paragraph and exit the macro if so
If rSentence.Start = rParagraph.Start Then Exit Sub

If you prefer to insert a new paragraph anyhow, even for the first sentence, then simply omit this command. Unlike the previous version, the way we're detecting the space(s) separating the sentences in this version will not cause a logical error even without this first sentence restriction.

Insert the new paragraph at the sentence

Since we already identified the initial sentence range, we can just use the InsertParagraphBefore method.

rSentence.InsertParagraphBefore

This method does exactly what the name implies. It does, however, extend the range backward one character to include the new paragraph marker.

Is that all?

Uhhh ... yeah, as far as the paragraph. Kind of underwhelming.

Side notes on inserting the new paragraph

Notice we did not need to use the StartOf method to navigate our invisible range variable to the beginning of the initial sentence. The above method automatically inserts the paragraph at the correct location since the rSentence range begins at the intended sentence.

Also, we could not use either the InsertParagraphAfter method or the InsertParagraph method. The former would put the paragraph break in the wrong place and the latter would have the undesirable consequence of deleting our sentence in the document since it replaces the range content with a paragraph marker.

Clean the table (remove sentence space)

The above insert method does not remove any spaces between the sentences. If we're writing a macro, it really doesn't make much sense to force ourselves to manually remove the space after we insert the new paragraph with the sentence. Let the macro do that work for us also.

With that said, I prefer to further let the macro catch other little typographical oospies. What does that mean?

It's "almost as easy" to check for and remove any number of spaces as it is to check for one. In practice, the approach ends up being harder because of a Word idiosyncrasy, but it's more general.

Working range

We use previously defined working range variable r for clarity, but a streamlined macro could reuse one of the other working ranges.

Get the first paragraph range

Huh? Didn't we already do that?

Yeah, but we also just split the paragraph with the last command. At this point in the macro, the range variable rParagraph spans both paragraphs, so we need to make sure we're working with the new "first" paragraph. The command is similar to assigning rParagraph earlier when we used the Selection except we're setting our new working range r based on the current paragraphs range rParagraph.

Set r = rParagraph.Paragraphs.First.Range

In this macro, the current insertion point (where the Selection is) resides in the sentence we just split off into its own new paragraph. Our working range r now spans only the first of the split paragraphs.

Collapse the range

In preparation to find the unwanted space(s), we need to "move" the range to be next to the intended space(s). The range r spans the entire new first paragraph, and we want to isolate any excess space(s) at the end.

The Collapse method for a range works just like the Selection version except it collapses a specific range variable. A collapsed range spans no document content (it's a little more complicated, but we'll work with that for now). In VBA terms, the Start and End positions will be the same.

r.Collapse ' Not done ...

But we need to collapse toward the end at the new paragraph, so we use the Direction option.

r.Collapse Direction:=wdCollapseEnd

We assign the value wdCollapseEnd (from another Word constants table) to the Direction option using a colon equals := symbol.

Range is now positioned at the next paragraph?

The insertion point is now positioned at the beginning of the next paragraph, but this occurs because a paragraph range always includes its paragraph marker at the end. After collapsing the range toward the end, it finishes just after the ending paragraph marker … which is the beginning of the next paragraph.

It is a little counterintuitive at first, but it makes sense in the context of boundaries. The end of one is the beginning of another something like the end of one day marks the beginning of the next.

Alternative move method

Often, more than one way exists to solve a problem. In this case, an equivalent command would be to just move the range to the end of the paragraph with the EndOf method.

r.EndOf Unit:=wdParagraph ' Alternative method (not used)

In this case, it's just a matter of preference since they result in exactly the same document position, but we won't go into any more detail since this method is not used.

Step back over the paragraph marker

The working range r is now positioned at the beginning of the next paragraph. We need to move back just inside the previous paragraph. A paragraph marker is a single character in Word, so we can literally just move the range by one character using the Move method.

' Step back past the paragraph marker next to any ending spaces
r.Move Count:=-1

Move collapses the range (which has no effect here since we already did it ourselves in the previous step) and moves it by a given unit and number of steps. The default is forward by one character (positive 1), but we specified the Count option as -1 since negative Count values move backward in the document.

Extend the Start over the spaces

Now we need to extend the range over the possible space(s) at the end of the split paragraph. The MoveStartWhile method allows us to specify a specific character.

r.MoveStartWhile Cset:=" " ' Not done ...

MoveStartWhile literally moves the Start position of the range "while" it keeps finding any character in the character set option Cset. We assign a space in double quotes " " to the option.

The default is to move forward by any number of characters, so we need to specify backward using the Count option.

' Extend working range over all previous spaces
r.MoveStartWhile Cset:=" ", Count:=wdBackward

The wdBackward constant is defined in another Word constants table. We need to separate the two options with a comma.

Check for a spanned space (kind of optional)

At this point after the move command, the range r will span any spaces (usually just one) at the end of the paragraph, but a small problem exists. We want to delete the space using the Delete method, but if no space exists, the action will still delete something. Mostly likely, it would delete a paragraph marker, since that the most logical reason for no space being present between sentences, but it would delete whichever character is to the left of the range.

Hmmm.

We could just assume a space will always exist and not worry about it, but that may return to bite you someday.

How?

If we run the macro on the first sentence of a paragraph, no prior space would exist. While we didn't mention this possibility earlier, it's part of the reason we excluded the first sentence of a paragraph. Does that solve the whole issue?

Ummm … mostly. In rare circumstances, formatting or special characters could confuse Word about the sentence structure, but it just feels icky to not take an extra step to make sure. We're already doing all kinds of fancy VBA stuff here, so one more itsy bitsy, tiny check more won't hurt, right? That way, we can rest better at night.

Check for a non-empty range before deleting?

How do we ensure the range r spans any spaces before attempting to delete them?

Conditional statement

We actually only want to delete the range contents if the range has something in it. A rough conditional statement might look like:

If the range has something in it Then
' Delete the range
End the conditional statement

Nothing should be deleted if the range is empty, so no otherwise (Else) part is included.

Empty range condition

A range is empty if it's Start and End positions are the same.

r.Start = r.End ' Is the range empty?

VBA interprets this as a True or False (Boolean) condition when it's used in a conditional statement context.

Non-empty range condition

Uhhh … that's not right. We want to delete something when the range is not empty. Acutally, we just add the Not (Boolean) operator in front of the condition.

Not r.Start = r.End ' Is the range not empty?

A Not operator just flips the True or False value of whatever comes after it. The fact that it is something fancy called an "operator" just means that it acts on something to give a (usually different) result.

Conditional statement

Converting our above conditional statement into VBA, we have:

' Check whether a range is not empty before deleting anything
If Not r.Start = r.End Then
' Delete the range
End If
Delete the extra space

Deleting the range contents is the easy part. We just refer to its Delete method.

r.Delete

The Delete method removes the spanned content from the document, which is our situation at this point in the macro. However, even if no content is spanned, the command still deletes the character to the left as if we manually pressed the Delete key (it's not emulating the key, but the effect is similar by design).

Mac Delete key caveat

For those using Word for Mac, the VBA Delete method acts like a “forward" delete as if it were used in Windows, deleting to the right in the document. The Delete key on Mac systems typically deletes "backward" in the document in most applications. To make it more confusing, Macs seem to interpret the Backspace and Delete keys as in Windows when using full-sized external keyboards (Mac keyboards change the respective key labels for clarity).

Fix a Word quirk

Unfortunately, Word will often reinsert a space automatically when it thinks we have improperly deleted text. This is often convenient in real-time editing, but it works against us more often than not in VBA. If a new space is inserted, we need to detect it automatically and delete it.

Get the previous character

We've already looked at conditional statements above, so let's just consider the condition. We need to know whether the character just before the (collapsed) range position is a space. Any range variable includes a Previous method that gives us previous document content relative to the beginning of the range.

r.Previous ' What is the previous character? Not done ...

The default unit is a character which is what we want, so we can omit the Unit option (it looks messier anyhow). The Previous method technically returns a document range, but we can get the plain text inside the range using the Text property.

r.Previous.Text ' What text is in the working range?
Previous character conditional statement

We need to know whether this character is a space " ", so the condition is:

r.Previous.Text = " " ' Is the character a space?

We use this in a conditional statement.

If r.Previous.Text = " " Then
' Delete the space Word reinserted
End If

We need to delete the previous character in the document, so we against use the Delete method. The difference this time is we need to specify one character backward in the document using a negative Count option.

If r.Previous.Text = " " Then
' Delete the space Word reinserted
r.Delete Count:=-1
End If

The default delete Unit is a character (from the Word units constants table), so we can omit it and just specify the Count option.

Shortened conditional statement

Since the command is short, we can condense it onto one line.

If r.Previous.Text = " " Then r.Delete Count:=-1

This command catches and deletes the extra space Word sometimes reinserts into our document while the macro is running.

Finish the macro

Now we just put the commands together for our improved version of the macro.

Sub NewParagraphWithSentence()
' Insert a new paragraph with the current sentence
' Does not move the current insertion point

' Work with the current sentence and paragraph ranges
Dim rSentence As Range, rParagraph As Range, r As Range
Set rSentence = Selection.Sentences.First
Set rParagraph = Selection.Paragraphs.First.Range

' Exit if already at the start of the paragraph
If rSentence.Start = rParagraph.Start Then Exit Sub

' Insert a paragraph before the current sentence
rSentence.InsertParagraphBefore

' Set the working range in preparation to delete any excess spaces
' Need to get the new first paragraph since we split the original
Set r = rParagraph.Paragraphs.First.Range
r.Collapse Direction:=wdCollapseEnd
' Step back past the paragraph marker next to any ending spaces
r.Move Count:=-1
' Extend the working range over all previous spaces
r.MoveStartWhile Cset:=" ", Count:=wdBackward
' Delete any excess spaces at the end of the paragraph
If Not r.Start = r.End Then
r.Delete ' Delete spanned spaces
' Catch and delete an extra space Word sometimes reinserts
If r.Previous.Text = " " Then r.Delete Count:=-1
End If
End Sub

The base of the macro consists of just a few commands. The main obstacle is properly detecting and deleting any space(s) separating the sentences. The result is a nice, convenient macro that I use almost every day. I assigned my version to Option+Return in Word for Mac or Alt+Return on Windows.

Improvements over the simple version

The earlier, simpler version in a previous article is fully functional, so what are we getting for our trouble in this improved macro? If you're interested in further refining it, see the extended content below.

Avoids screen jitter

The earlier approach occasionally caused a sentence to jump up into the prior paragraph and back down. This revised version above avoids any such unsightly behavior.

Fixes insertion point side effect

When used on the first sentence of a paragraph, the insertion point would jump to the beginning of the sentence even if no paragraph was added. It's an odd side effect when no new paragraph is inserted. This version keeps the insertion point in place, so you can keep editing. The result is more intuitive.

Removes extra spaces

The previous macros assumed a single space between sentences, but the improved version catches and corrects more than one space automatically.

Does not move the insertion point

You may like the insertion point finishing macro at the beginning of the new paragraph, but it seems more intuitive to just keep the insertion point wherever we're typing.

Any gotchas?

Before rushing to implement our new productivity booster, we should consider any special cases just in case they could cause any problems later. This is particularly important for macros that delete or rearrange content. We don’t want to lose any precious work in our manuscript all because we didn’t think about the steps just a little bit more. Today’s macro is less of a concern since we only delete one character in the document, but accidents happen.

What if a starting selection exists?

A common special case is whether the macro runs with text already selected, intentionally or unintentionally. Sometimes our fingers just hit weird keys before we tap a shortcut, or we selected something and ran the wrong macro.

In this revised macro, we're referring specifically to the first sentence or paragraph based on the initial position in the document, so it does not matter if a selection already exists.

What about the last sentence of a paragraph?

If the insertion point is anywhere inside the last sentence (assuming it’s not the only sentence) of a paragraph, it will normally have a preceding space just like a “middle” sentence does. For this macro, there is no difference between a middle and a last sentence, so nothing bad should happen.

What about the first sentence of a paragraph?

Logically, we would not run the macro on the first sentence of a paragraph since it already begins a new paragraph, but what if we tapped the shortcut accidentally. What would happen?

Our new macro detects the first sentence and just exits the macro without doing anything, so there is no problem.

If you chose to remove that check, it would just create an empty paragraph above the current. The non-empty range check would not allow it to delete any non-space characters, so this is not a problem.

Whether the macro should create an empty paragraph above the current for the first sentence is a matter of preference. I find it a little awkward since I already have a macro to do that which is tailored for that specific task.

What if only one sentence exists in the paragraph?

For this macro, one sentence would fall under the "first sentence" case above by default, so there is no problem.

What if no sentence exists at the insertion point?

For this macro, the first sentence check would identify it as the first (kind of empty) sentence range which would probably consist of just a paragraph marker (yes, Word includes them in sentence ranges and selections). The check would then just exit the macro, so there is no problem.

A more elegant variation

My own version is more similar to the one above, but the need for a spacing correction pops up enough in other macros that I extracted those steps into a separate function. Two previous articles cover different versions of such a function. Some similarities exist between them, but one simply deletes the spaces for a range and reverses Word's attempted spacing correction. Another just works with a given paragraph.

We will apply the latter since we know we're already working with a specific paragraph. The result is an elegant macro much simplified compared to the original.

Calling the delete function

Let's summarize the mentioned function to delete any superfluous spaces at the end of a paragraph:

DeleteParagraphEndSpaces(SomeParagraph) ' Not done ...

This macro requires a paragraph to be "passed" to it, often as a variable, so it knows which document paragraph to process and check for unwanted space(s) at the end. We place the paragraph variable or reference inside the parentheses (technically, they are not required if we're not storing or using the function within another statement, but it is standard).

Our function returns how many spaces were deleted, but we do not need this information, so we effectively discard the result by not storing it. In the current usage, it's essentially a fancy macro which we use to work on a specific, provided paragraph. We cannot assign such a function to a shortcut or a ribbon button, but they're still super important. Any complicated macro will likely be broken down into more bite-sized pieces like this. It's why they were invented many years ago.

Which paragraph?

From above, our initial paragraph range was rParagraph, but we split the paragraph with the InsertParagraphBefore method. We need to refer to just the first paragraph using the range's Paragraphs collection.

rParagraph.Paragraphs ' Not done ...

We need the first paragraph as we did up top, so we reference the First property. Notice range variables and the Selection share many similar properties and methods.

rParagraph.Paragraphs.First

We do not need to refer to the range of the paragraph since the above macro wants an actual Paragraph reference.

Calling the function

Adding the paragraph argument, our "function call" is:

' Delete any excess spaces at the end of the split paragraph
' Need to get the new first paragraph since we split the original
Call DeleteParagraphEndSpaces(rParagraph.Paragraphs.First)

The new first paragraph reference is placed inside the parentheses to tell the function exactly which paragraph we want to modify. The keyword Call is optional but probably clearer (that we're using a separate function).

In the longer version of the macro above, we essentially replace everything below the new paragraph insertion with this function call. As a bonus, we get to use the function in other macros and save a lot of work. The macro even looks better.

Final new paragraph with sentence macro

That’s a lot of talking for a small issue, but the fixed version handles all paragraph sentences correctly and works quite intuitively.

Sub NewParagraphWithSentence()
' Insert a new paragraph with the current sentence
' Does not move the current insertion point

' Work with the current sentence and paragraph ranges
Dim rSentence As Range, rParagraph As Range
Set rSentence = Selection.Sentences.First
Set rParagraph = Selection.Paragraphs.First.Range

' Exit if already at the start of the paragraph
If rSentence.Start = rParagraph.Start Then Exit Sub

' Insert a paragraph before the current sentence
rSentence.InsertParagraphBefore
' Delete any excess spaces at the end of the split paragraph
' Need to get the new first paragraph since we split the original
Call DeleteParagraphEndSpaces(rParagraph.Paragraphs.First)
End Sub

It's a nice solution over the above version and almost looks simple. Of course, we are off loading the "hard work" of detecting and deleting the excess space(s) to a separate function, but that function can be reused in other macros.

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.