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

Delete sentence more

Word • Macros • Editing
Peter Ronhovde
12
min read

What if I took one of my favorite Word macros, deleting sentences, and betterified it! (It’s a word. Look it up … no, sorry. Please don’t.)

See an earlier article for an introduction to deleting sentences and this article on how to create the empty macro assigned to a keyboard shortcut (later content will cover manually adding keyboard shortcuts to existing macros allowing us to skip that step).

Some things are harder to explain in text than they are in person, and this article uses a few more concepts at the same time than the earlier macros. It’s not too much if you’re a programmer, but I still take time to explain most of the new details for the Word user that wants to up their game.

Thanks for your interest

This content is part of a paid plan.

Handle dialog naturally …

How to make the original delete sentence macro better?

Well, I’m a writer, and I write dialog a lot, so I’d like my sentence macros to naturally handle dialog and not delete double quotes unnecessarily.

It seems like a small task, but these little niceties add up when you’re on a roll writing or editing.

I will refer to quotes as I talk, but the resulting macro could also be modified for parentheses with a slight tweak.

What does “natural” mean here?

If the dialog amounts to only one sentence, then delete everything as normal along with the quotes.

Deleting a single dialog sentence

But if more than one sentence is inside double quotes, delete the sentence but not the quotes.

Deleting a sentence within dialog

Simple delete sentence macro

For those that haven’t seen it, the earlier simple blog macro to delete the current sentence was:

Sub DeleteSentence()
  ' Delete the current sentence in the document
  Selection.Expand Unit:=wdSentence
  Selection.Delete
End Sub

This is functional, but it makes no allowance for our dialog.

Detecting the punctuation

We need a way to detect the punctuation, but we have to handle a detail first, or it will likely thwart our efforts.

Trim extra spaces

Word automatically handles some spacing between sentences as we modify text. For selections, Word includes any trailing space(s) in a sentence selection (and actually any white space which includes empty paragraph markers), so before checking for any double quotes, we have to account for the extra spaces on the right sight of a selected sentence.

Basically, we just need to move the end of the Selection backward if there are any spaces which introduces a new, lesser-used VBA command in Word.

  Selection.MoveEndWhile CSet:=" " + vbCr, Count:=wdBackward

Let's unpack this command.

The MoveEndWhile and MoveStartWhile commands both require a character set specified using Cset. Either command checks each successive character and adds or removes it from the Selection depending on the direction specified with Count. The commands stop when they find any character not included in the set.

Don’t forget the symbol := is how we assign a value to the necessary parameter. We usually need to specify the desired characters in double quotes unless we need to include any special characters like paragraph markers (which we do, read on).

A small problem is the expanded selection will include any empty paragraph markers for sentences at the end of the current paragraph. The special character vbCr is a VBA constant for a return character. We use a + to "add" the two "strings" together (called concatenation for strings), so the command keeps shrinking the end of the selection for either a space or an paragraph marker on the end.

Count is the maximum number of characters matches to move, but the wdBackward constant is a special case telling the command move backward with no upper limit on how many of the Cset characters to add or remove from the Selection.

Double quotes in Mac and Windows

Unfortunately, double quotes are stored differently between Mac and Windows systems which includes Microsoft Word.

In Word for Mac, a left curly double quote is Chr(210) and a right is Chr(211).

In Word for Windows, a left curly double quote is Chr(147) and a right is Chr(148).

If you want to be complete, you can include Chr(34) which is a straight (or “keyboard”) double quote just in case. This is probably a good idea because occasionally Word's smart quotes feature doesn’t catch a straight double quote to convert it to a curly double quote. For example, it won’t make the conversion after the fact if you’ve tapped undo.

Note Chr stands for “character” which is a standard function in many languages. It allows us to specify many non-keyboard characters using numbers from different constant sets, but the default character sets can vary especially between different operating systems like Mac or Windows.

Remove the left or right double quote

Now we check and possibly remove the double quote, but the tricky part is that we only want to remove it if it occurs on one side.

Some simplifying assignments

First, we’ll define three constants for the double quotes to make everything read easier for a human.

  LeftDQ = Chr(210)
  RightDQ = Chr(211)
  StraightDQ = Chr(34)

Now store the first and last characters of the current Selection. As a bonus, you only have to make a change above if you switch to a Word for Windows (see short article explaining how to automatically do this).

  FirstCharacter = Selection.Characters.First
  LastCharacter = Selection.Characters.Last

Character and paragraph ranges comment

If you’re paying close attention, you might notice in our very first macro when we selected the first paragraph that we used an additional “range” property given on the end.

  ' Previous use of Selection object range on a paragraph
  Selection.Paragraphs.First.Range

The difference is a paragraph is an object with its own properties where a character is just a character, so it’s already a “range” when we return it using the Characters collection of the Selection.

Using Ranges (see supplementary article) is generally a better way to write VBA macros rather than relying on the Selection object (see comment below).

Detect the double quote

Now detect whether the identified first and last characters are the appropriate double quotes and store these results as true-false (called Boolean) values.

  IsFirstCharacterQuote = FirstCharacter = LeftDQ Or FirstCharacter = StraightDQ
  IsLastCharacterQuote = LastCharacter = RightDQ Or LastCharacter = StraightDQ

For those new to programming, we checked whether the FirstCharacter is the same as a left double quote or the opposite for the LastCharacter.

Boolean true-false values comment

The results are stored as true or false values in the variables IsFirstCharacterQuote or IsLastCharacterQuote.

These variables are called “Boolean” variables, and we can use them in logical statements allowing us to make decisions in our macros depending on the current state of our document or even within the macro.

The most important types of logical statements where we’ll they will be used include: “If … Then” conditions, “Do … While (or Until)” loops that allow us to run the same steps many times as needed, and more (see a later article reviewing the relevant commands).

Or statement with logical clauses comment

Note also how we checked for either the curly or straight quote using an “Or” between them. An Or like this results in an overall true value if either or both of the statements is true.

Assignments comment

All of the above assignments are not strictly required since they could just be included manually in the commands below.

Sometimes, they give a tiny efficiency boost, but usually they just make things easier to read for us humans, which is important when you come back to your own macro after a long time.

However, you won’t notice a practical difference in macro execution times unless you have a very busy macro.

Remove the detected double quote

Finally remove the double quote if it only occurs on one side of the sentence.

  If IsFirstCharacterQuote Xor IsLastCharacterQuote Then
    Selection.MoveStartWhile CSet:=LeftDQ + StraightDQ
    Selection.MoveEndWhile CSet:=RightDQ + StraightDQ, Count:=wdBackward
  End If

There are other ways to modify the Selection before deleting the sentence text, but this is easy since we had already introduced the MoveEndWhile command earlier. It’s also quite general purpose.

Xor statement with logical clauses comment

How did we handle testing for a double quote only on one side?

An Xor is called "exclusive or." It is not often used, but it is perfect for this situation. Basically, it acts like a regular Or except it gives a false result in both conditions are true. (That is, Xor results in a false if either or both conditions are true, but it yields a true result only if one condition is true.)

For us, this means it's true if only one side has a double quote.

Result allowing for double quotes

Putting it all together in order we get

Sub DeleteSentenceEnhanced()
  ' Delete the current sentence in the document respecting double quotes or parentheses
  ' on one side of a sentence
  
  ' Select the current sentence in the document
  Selection.Expand Unit:=wdSentence
  
  ' Remove any trailing spaces from the selection
  Selection.MoveEndWhile CSet:=" " + vbCr, Count:=wdBackward
  
  ' Define left and right double quotes to use below
  ' Change left and right curly quotes to Chr(147) and Chr(148) on Windows
  LeftDQ = Chr(210)
  RightDQ = Chr(211)
  StraightDQ = Chr(24)
  
  ' Detect the first and last characters of the selection
  FirstCharacter = Selection.Characters.First
  LastCharacter = Selection.Characters.Last
  
  ' Check whether the first and last characters of the selection are double quotes
  IsFirstCharacterQuote = FirstCharacter = LeftDQ Or FirstCharacter = StraightDQ
  IsLastCharacterQuote = LastCharacter = RightDQ Or LastCharacter = StraightDQ
  
  ' Test whether a double quote exists on only one side
  If IsFirstCharacterQuote Xor IsLastCharacterQuote Then
    ' Remove the quote from either side
    ' Nothing happens on the side with no double quote
    Selection.MoveStartWhile CSet:=LeftDQ + StraightDQ
    Selection.MoveEndWhile CSet:=RightDQ + StraightDQ, Count:=wdBackward
  End If
  
  Selection.Delete
End Sub

I also added some comments to make it clearer what is going on. It’s tempting to omit them when your creating your macros, but it’s a good practice since you may forget what you were thinking later if you ever need to revise or tweak the macro.

Selection versus Ranges caveat

I use the Selection object in many of the blog articles because it an easier approach for beginners. I am not recommending experienced macro users rely on the Selection object (see Functions and Ranges comment below).

Over reliance on the Selection within a macro can make your screen “flicker” in some more complicated macros.

Morning importantly, using the Selection can be a little dangerous since we’re deleting the selected text when we’re done, and no writer wants precious words stricken from their novel without their knowledge because of an oversight when writing the macro.

Further enhancements

Depending on how refined you want your macro to be, there are a few other tweaks that will make it even nicer to use.

Spacing tweaks

In many of my macros, I usually like to add steps to handle little special cases.

Word often does a good job of adjusting the local spacing to an expected result, but occasionally in macros the default behavior will leave a trailing space at the end of a paragraph or something similar. I prefer to avoid this behavior (and find it annoying when writing some macros). Why not let the macro handle that for me automatically?

Honestly though, this tweak is more of a perfectionist thing than being absolutely necessary.

Functions and Ranges

What is my personal version of this macro like?

If you’re inclined, I use ranges and write the punctuation handling parts as functions, so I can use the same functions across multiple macros.

These changes make the macro tidier and easier to read since the macro itself is not so long. Although, I admit my current version is a little bit of a Frankenstein approach since I developed the enhancements over time.

Using ranges doesn’t make as much of a practical difference with this macro as with some others, but they do make the functions more general purpose and easier to implement since they don’t have to rely on the current or even the evolving status of the Selection object.

Parentheses tweak

I mentioned changing this macro to work with parentheses. First include the new character definitions.

  LeftParen = "("
  RightParen = ")"

We can skip the Boolean assignments since the character check is simpler now.

  ' Test whether a parenthesis exists on only one side
  If FirstCharacter = LeftParen Xor LastCharacter = RightParen Then
    ' Remove the parenthesis from either side
    ' Nothing happens on the side with no parenthesis
    Selection.MoveStartWhile CSet:="("
    Selection.MoveEndWhile CSet:=")", Count:=wdBackward
  End If

As a little bonus, this will skip consecutive nested parentheses on either side as long as no other characters exist between them.

Personally, I would add this to the bottom of the above macro to account for both cases.

Final macro

The final result allowing for either double quotes or parentheses is:

Sub DeleteSentenceEnhanced()
  ' Delete the current sentence in the document respecting double quotes or parentheses
  ' on one side of a sentence
  
  ' Select the current sentence in the document
  Selection.Expand Unit:=wdSentence
  
  ' Remove any trailing spaces from the selection
  Selection.MoveEndWhile CSet:=" " + vbCr, Count:=wdBackward
  
  ' Define left and right double quotes to use below
  ' Change left and right curly quotes to Chr(147) and Chr(148) on Windows
  LeftDQ = Chr(210)
  RightDQ = Chr(211)
  StraightDQ = Chr(24)
  
  ' Detect the first and last characters of the selection
  FirstCharacter = Selection.Characters.First
  LastCharacter = Selection.Characters.Last
  
  ' Check whether the first and last characters of the selection are double quotes
  IsFirstCharacterQuote = FirstCharacter = LeftDQ Or FirstCharacter = StraightDQ
  IsLastCharacterQuote = LastCharacter = RightDQ Or LastCharacter = StraightDQ
  
  ' Test whether a double quote exists on only one side
  If IsFirstCharacterQuote Xor IsLastCharacterQuote Then
    ' Remove the quote from either side
    ' Nothing happens on the side with no double quote
    Selection.MoveStartWhile CSet:=LeftDQ + StraightDQ
    Selection.MoveEndWhile CSet:=RightDQ + StraightDQ, Count:=wdBackward
  End If
  
  ' Now exclude a parenthesis on one side
  ' Define left and right parentheses
  LeftParen = "("
  RightParen = ")"
  
  ' Reset the current first and last characters of the selection to allow
  ' for parentheses detected inside double quotes
  FirstCharacter = Selection.Characters.First
  LastCharacter = Selection.Characters.Last
  
  ' Test whether a parenthesis exists on only one side
  If FirstCharacter = LeftParen Xor LastCharacter = RightParen Then
    ' Remove the parenthesis from either side
    ' Nothing happens on the side with no parenthesis
    Selection.MoveStartWhile CSet:="("
    Selection.MoveEndWhile CSet:=")", Count:=wdBackward
  End If
  
  ' Finally delete the resulting selection
  Selection.Delete
End Sub

That's it.

It's a nice enhancement to when working in a novel since almost all novels have lots of dialog. Handling parentheses is a little bonus that require much extra work.

Macro length comment

This macro is getting a little long. My comments make it seem longer than it actually is. Using functions along with ranges as mentioned above would tame the length some as well as giving you tools to use in other macros.

Don’t cringe at the length any more than you cringe at a day’s work at the keyboard since we build up the macros one step at a time. The number of steps required to do the job is just the number of steps required to do the job.

There’s also a certain amount of satisfaction when you’ve created a nice, functional macro to help you in your writing.

Another special case

The above definitely works, but if a line of dialog ends with a dialog tag such as," she said. Then the steps above will not properly select the entire sentence. Rather, it will leave a left double quote.

Let me know if you'd like to see this case handled in the same macro. It seems a bit of overkill for the way I use dialog personally, I am usually a proponent of having the macro do everything you need within reason. I didn't want to overwhelm everyone, so I stopped with the above.

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.