Trimming sentences faster in Word will obviously expedite the editing process for a manuscript. Toward this end, we create macros to delete to the beginning or ending of a sentence while intuitively handling common sentence punctuation.
Thanks for your interest
This content is part of a paid plan.
Delete part of a sentence
Word includes some standard keyboard shortcuts for manipulating words or paragraphs. Sentences are also a rather fundamental writing unit, but Word has no standard shortcuts for manipulating them. A few hidden commands exist allowing us to navigate between or select sentences, but that the extent of the list. Creating additional macros to improve the sentence editing experience is a worthy endeavor.

To my chagrin, deleting to the end of a sentence is probably one of my more used macros, so you should definitely try it. The base macros from the previous versions are short and pass over a few details, so we enhance them to better account for sentence punctuation as well as make them a tiny bit safer to use.
Create the empty macro
If you're starting from scratch, a previous post covers creating an empty pair of macros:
While VBA commands are generally easy to read, the single quote on the second line starts a comment where we can add further explanation as desired. VBA ignores the comment, so we'll start our commands on the blank line below it. We'll focus on the first version and then explain the differences in the second.
Delete to the end of a sentence
We don't want to expand the selection over the entire sentence before deleting it, so we need a way to select only part of a sentence. A standard Word command exists called SentRightExtend (see our brief summary of the related commands) to extend a sentence selection, but it works with the selection on screen. It also does not account for any punctuation by itself, so we'll make our own with regular VBA.
Define a working range
Using the Selection (see our brief review) repeatedly within a macro can cause the screen to flicker as the selection changes in real time. The current macro would most likely have limited to no screen flicker even without switching over to using a document range variable, but it's better to be general, and it does not hurt anything.
We use Dim to define a variable in VBA and As Range defines the data type. Technically, we do not have to include this line in standard VBA, but as your macros grow in length, it's a good practice to be specific. The first time you spend more than a few seconds tracking down a misspelled variable, you'll appreciate it.
What is a Range?
A Range (see our brief introduction for more explanation) is a specific "object" data type in VBA which is an internal representation of a span of document content. A Range is fundamentally defined by Start and End positions in a document, but it contains additional data (properties) and actions (methods) that allow us to manipulate them in the document.
A Range acts like an invisible selection we can modify independent of the VBA Selection (unless any changes overlap). Only one Selection exists per document, but we can define as many range variables as we need for a macro, and changes to a range are only visible in the document when we specifically change the content.
When using the range, the various methods to manipulate it act like Word does when working with the document selection. Keeping this in mind will guide us when envisioning the correct macro steps later.
Variable names
Generally speaking, use variable names that make sense and don't make you scratch your head later wondering what you were thinking at the time. Our current name rSentence implies it is a range related to a sentence. Roughly, the lowercase r of rSentence implies the range will change as we step through the macro, but VBA does not care as long as we do not try to claim one of its reserved words (like If or Selection).
Short names are nice when they are clear, but it's probably better to veer toward descriptive over short. On the other hand, when I am working with only one range variable in my own macros, I will often use just "r" as a typical name. I will add a descriptive comment where it is defined if there is any ambiguity.
Define the range based on the current selection
We plan to manipulate the current sentence, so we want the initial working range to match the current selection or insertion point in the document.
We need to use Set rather than just an equals = sign because a Range is an object in VBA with additional information beyond just a typical value like a number or plain text. While the Selection is like a document range, the Selection is more specific. Thus, we Set the rSentence variable to the Range of the Selection for the correct match.
Picking the correct method
Sometimes VBA will have a few similar methods to carry out a desired step perhaps with some subtle differences between them. Part of writing good Word macros is picking the correct command for the task at hand. Early on, I floundered, but I eventually discovered Word VBA already had some nicely targeted commands I could leverage for my specific needs. It's easy to overlook some of them, but if we'll just dig a little, we can discover them and pounce ... uhhh, sorry, the flounder metaphor is faltering.
We can use the correct method at the correct time. There, that's better.
Extend the range the end of a sentence
We need a way to just select part of a sentence. We could use a standard range extension command like MoveEnd which does what the name implies, but we can do even better for this macro given our specific need to select to the end of the current sentence but no farther.
Use the EndOf method
We’ll leverage a lesser used move Range method called EndOf to setup the delete step later.
Given the preposition ending the method name, it's not surprising the method requires a relevant document unit. Several standard ones are defined in the WdUnits constants table. We assign the desired constant using the Unit option name with a colon equals := symbol. Of course, in this macro, we'll use wdSentence, but the concept could easily be extended to other document unit types such as wdParagraph.
EndOf is primarily a movement method, but it does allow us to extend the range instead.
The Extend option requires a constant from the short WdMovementType constants table. It defaults to wdMove which collapses the range and just moves the insertion point, but we want wdExtend which extends the range from the End position.
Contrast with the MoveEnd method
As an aside, we could accomplish something similar using the regular range MoveEnd method instead. Without going into much detail, the command would be:
MoveEnd only moves the End position of the range leaving the Start position unchanged. Thus, the method effectively extends the range. Sounds good so far.
What's the problem?
The two approaches are not quite the same. The MoveEnd method extends to the next specified Unit regardless of the current End position of the range in the document. The EndOf command understands if it is already at the end of a sentence and will not extend the range any farther if so.
Using MoveEnd would not be wrong per se, but we would need to add an extra step or two to account for the special case at the end of the sentence. Why bother when EndOf already works exactly the way we need for this macro?
Allow for punctuation marks
Now that we've extended the range to the end of the sentence, we want to tweak it to account for any punctuation. We previously created a related macro to delete a full sentence while accommodating double quotes or parentheses.
When deleting only part of a sentence, I prefer to delete just the text of a sentence not the end of sentence punctuation. We're want to trim a valid sentence not delete it entirely. In the process, it's easy to include double quotes to naturally handle dialog as well as a few other punctuation marks. For the delete to the start of a sentence version, we mostly only need to exclude quotes and parentheses, so we'll work on the end of the sentence version first.
What's the plan?
After we’ve extended the range to span all characters up to the end of the sentence (which coincides with the beginning of the next sentence in Word's parsing scheme), we want to move the End position of the range backward to remove all punctuation characters. When solving this problem, we should understand that Word considers the current sentence to extend all the way to the beginning of the next sentence including any spaces or other characters separating the sentences.
Why the squirrely back and forth?
Why are we extending the range forward only to move it back over the end of sentence punctuation?
We're taking advantage of Word's internal sentence detection logic. Not that word is perfect at it, but the simpler version of this macro extended the Selection directly to end of sentence punctuation. It seems more direct—just go immediately to the target end of sentence punctuation—but the relevant method wasn't smart enough to discern between the actual end of a sentence or any decimal numbers or abbreviations inside a sentence. Writing our own logic to interpret such document content is more complicated that we want to tackle. The improved version remedies most of those cases, at least for any sentences Word can properly recognize itself.
Character set
The character set is a little long, so it's convenient to store it in a separate variable first, so the upcoming move command is a little easier.
We will need a character set stored as a plain text string. The order does not matter for our character set since the later command is looking for any of the listed characters. Now what characters?
Adding plain text strings (of characters)
We add strings (of characters) using the + sign mimicking how we add numbers. This is called concatenation when used with strings where we basically just shove them together and call it another string. For example, "a" + "b" = "ab", but everything has to be a string for it to work. The ampersand & also concatenates strings (also like "a" & "b" = "ab"). It is slightly more forgiving when concatenating strings in VBA, but it just looks messier.
Regular end of sentence punctuation
We want to exclude typical end of sentence punctuation: period ".", question mark "?", or exclamation point "!". Other such punctuation marks are closing parenthesis ")" and a square bracket "]". All of these are plain text characters, so we can just smash them together into one string as ".?!)]".
This stores the string in double quotes in the TrimCharacters variable, but we're not done yet.
Paragraph markers
Word includes a trailing paragraph marker in a selection for any sentences at the end of a paragraph. In fact, it will include all paragraph markers of any empty paragraphs that follow that last sentence. This default behavior is counterintuitive to me, but at least Word is smart enough to not delete the trailing paragraph marker if the selection is deleted.
The paragraph marker needs to be removed from the range for our macro, or we won’t be able to trim the other punctuation marks in front of it. The move while method below would immediately stop when it encounters the vbCr character at the end if it is not in the character set. One alternative would be to just move backward one character and omit the paragraph marker, but including it in the character set also catches the less common case of multiple paragraph markers.
A paragraph marker is defined as vbCr (i.e., a return character) in a miscellaneous Word constants table. Since it is a special character, we need to add (concatenate) it manually to the trimmed characters string.
End of sentence spaces
Another necessary character to remove is a space " ". In a selection, Word automatically includes any trailing spaces, and range extensions behave the same. Like the paragraph marker above, this is more of a practical choice since the move while method would immediately stop at a space if it were not in the character set. Now our TrimCharacters variable looks like:
It's a little subtle, but the space is included as plain text inside the double quotes.
Double and single quotes
We want to naturally handle dialog quotes, but how do we tell VBA to exclude them?
A straight single quote would be easy. Just include it in double quotes like normal "'", but we need to include all the other variations, so we'll just treat it the same as the others to avoid any confusion.
What's the problem?
We use double quotes to define a plain text string of characters like "abc", so how do we specify a double quote character?
VBA has a special notation where we can specify a straight double quote as two double quotes inside another pair of double quotes ““””. Uhhh … and that’s not confusing at all, right? I suppose it's okay once you get used to it, but I won't or haven't. It’s clearer (to me) to just refer to quote characters by number.
Older way (not better)
Many languages have a Chr(…) function to translate the computer's numerical representation of a character to the text we see on the screen. This function works for most regular characters. For example, straight single and double quotes are Chr(39) and Chr(34), respectively, but the "curly" left and right quotes have different values between Windows and Mac systems. We created some double quote functions to make using them easier in VBA. Despite some information to the contrary, they are available when using Chr(…), but it's just not necessary when a more convenient function exists.
More convenient character function
It's easier to just use the more general ChrW(…) function which literally means "wide" character, meaning the underlying numerical representation uses a bigger number. This function uses Unicode character codes allowing many more characters. The respective numerical values for quotes are the same between Word for Windows and Mac which are summarized below:
- Straight double quote " → ChrW(34)
- Left double quote “ → ChrW(8220)
- Right double quote ” → ChrW(8221)
The character codes are similar for single quotes.
- Straight single quote ' → ChrW(39)
- Left single quote ‘ → ChrW(8216)
- Right single quote ’ → ChrW(8217)
To make using them easier, we define the respective characters using VBA:
This is not strictly required in standard VBA, but it is clearer. When using Dim, we can add more than one variable declaration on a line, but we need to separate them by commas and give a type "As String" (or whatever) for each variable. If we don't give a type, it will be a generic "Variant" type by default, which is usually okay, but it might cause a few small issues such as with function arguments.
Technically, these are variables as declared, but I prefer to put off declaring constants to a separate article. Now we assign the respective character values from above to each variable.
Command notation shorthand
We also took advantage of a special colon : command separation character. When it is used, VBA treats each part separately, but don't go crazy with it because overuse can make some dense, hard-to-read steps you may regret later. We used them here mostly because the assignments are so similar, and I didn't want to take up eight lines defining everything.
Best way (not covered here)
The definitions above still take four lines in a macro, but they won't change (probably ever), so why not define them as global constants. That is, we define them as constants not in each macro where they are needed but for all macros in the module (a group of macros in the VBA editor). We won't need to redefine them each time they are used.
What quote characters are we excluding?
For the end of sentence macro, we want to exclude the right single and double quotes. We'll also exclude straight single and double quotes. If they occur at the end of a sentence, it is much more likely they are on the right side of a quotation. Since the straight quote characters lacks any associated direction, it's more consistent with the intention of the macro to include them.
For the delete to sentence start macro, we want the left single and double quotes but also the straight quotes.
Similar to above, if a straight quote appears at the beginning of a sentence, we should assume it is starting a quotation and exclude the characters from the partial sentence deletion.
Overall excluded characters
Putting all these characters together, our string of excluded punctuation and other marks when deleting to the end of sentence is:
Excluding the punctuation marks
After all that explanation, we finally remove the punctuation marks from the end of the range by moving its End position backward in the document. The relevant command is the MoveEndWhile method.
MoveEndWhile does what the command name implies. It will keep moving the End position of the rSentence range while (as long as) it keeps finding any of the characters specified in the Cset option. We'll assign our TrimCharacters variable to the character set option Cset.
We need to move backward in the document, so we add the Count option separated by a comma.
Assigning Count := wdBackward sets it to a special constant (from yet another Word constants table) that tells the command to move as many as necessary backward in the document while it keeps finding any characters given in Cset. In general, we could specify a maximum number of characters to move past with a positive number moving forward and a negative number moving backward.
Advantage of using MoveEndWhile
Using the MoveEndWhile method has at least two advantages. First, it's concise and yet relatively easy to read once we understand the options. Second, it works for any combination of trimmed characters. We could hammer in our own version, but we'd either have to make it super messy testing for each possible character or assume a reasonable punctuation order. MoveEndWhile handles all that for us.
Reinclude spaces (optional)
When attempting to trim punctuation marks off the end, we do not generally know whether the command will remove anything other than a paragraph markers or spaces. We needed to trim those characters temporarily, so the punctuation could be detected with the same command.
Since Word includes ending spaces in a selection by default, it is consistent with that behavior for us to extend our working range back over any trailing spaces immediately after the rSentence range. Basically, we just need to extend the End position forward but only for spaces. We use the MoveEndWhile method again but just specify a character set of a space " ".
We're moving forward by default, so we omit the Count option. Using MoveEndWhile like this will include all trailing spaces which is exactly how Word would do it.
Consistency with Word
While this extra step for spaces is optional, it is good to be consistent with how Word works because that is what people expect. Even when we're creating macros just for ourselves, we have a trained expectation. Unless there is a solid reason to do something different, we should probably maintain that consistency.
However, I personally make an exception with regard to emulating Word's normal behavior with sentence ranges. I do not agree with Word including trailing paragraph markers in sentence selections, so I omit them in my own macros. This is still partly consistent with Word in a practical sense since Word is often smart to not delete the paragraph marker even when a sentence selection including one (or more) is deleted.
Delete the partial sentence range
We've seen the Delete method before, but for completeness it is simply:
It's almost anticlimactic at times to finish the macro, but if you're sad already, we do have an exception to consider.
Check for a non-empty range before deleting?
What if no sentence range exists by the time we're done trimming our working range?
Admittedly, it would be a nonsense "sentence" because it would have only contained punctuation, but it could happen.
What's the problem?
Even if the final range spans nothing, the Delete method will still delete something. Mostly likely, it would delete a paragraph marker (the most logical reason for no sentence being present), but it would delete whatever was next to the insertion point.
Hmmm.
Detecting an empty range
We actually only want to delete the sentence range if it spans at least some document content. How can we detect an empty range?
If the Start and End positions are the same, then the range is empty. If not, the range contains something. Since we're working in text documents, the contents are text in all likelihood. Both positions are numbers as literal character positions in the document, so we just need to check whether the two values are equal.
VBA treats this as a True or False (Boolean) condition when it's used within a conditional statement. Our conditional statement would look something like:
Nothing should be deleted if the range is empty, so no Else part is included. Putting it into a more VBA-like statement, we have:
Uhhh, but this condition is for an empty range. We need the opposite.
Use a Not to detect a non-empty range
We include a Not (Boolean operator) to flip the True or False value of the condition. Just place it in front of the condition.
With the Not included, it doesn't read as much like English, but it's still easy enough to understand.
If we don't have any extra steps to do, the conditional statement is simple enough that we can condense it into one line:
We could extract the empty or non-empty range condition into a separate function, which is convenient, but we just use it as is to avoid referencing yet another article.
Delete to Start of Sentence
The parallel macro to delete to the start of the sentence is nearly the same, but we need to tweak the steps in a few places and add a step before we finish.
Extend the range to the beginning of the sentence
The sibling command to extend the Start of the range backward in the document to the beginning of the current sentence uses the StartOf method:
It has the same behavior and options as EndOf which was explained above. We specified a wdSentence unit and used the Extend option to extend not just collapse and move the range.
Revised trim characters
We don’t have end of sentence punctuation marks, so we can reduce the number of trimmed characters to an open parenthesis or square bracket and the start quotation characters.
We use this revised set of trimmed characters with the MoveStartWhile method:
As with MoveEndWhile method in the other version above, MoveStartWhile keeps moving the Start position of the range forward in the document as long as it keeps finding any of the characters specified in Cset. We need to remove the characters from the range, so we move the Start position forward in the document. Since forward is the default direction, we can omit the Count option.
Capitalize the new sentence
After we’ve deleted to the beginning of a sentence, we will usually need to capitalize the new first word of the sentence. It won't take long to get annoyed with this step, so we should make VBA do it for us.
Sentence range is empty after deletion
After the working range is deleted from the document, it still exists as a collapsed range at the position of the deleted text. This range is necessarily positioned at the new first word of the trimmed sentence. We need to capitalize that word.
Capitalizing the new first word
Capitalization is handled by the Case property of the range.
In common help-page fashion, the descriptions in the list of VBA case constants are terse (details matter when writing macros). In short, the constants wdTitleSentence or wdTitleWord are probably best suited for our purposes, but they may not exactly like we would expect in all situations.
Fortunately, our current collapsed rSentence range must be at the beginning of the trimmed sentence because we deleted everything at the beginning of the sentence. If a range is collapsed like ours, the Case property will apply to the current adjacent word. For us, this is the first word of the trimmed sentence.
The constant wdTitleSentence capitalizes the first word of each sentence in the range. The constant wdTitleWord makes the Case property capitalize the first letter of each word in a range. Since our working range is already collapsed at the first word, both of these would work for us.
When to use the Case property (in this macro)
Since we only need to capitalize the new first word of the sentence if we delete something, we should include this step along with the delete step in the non-empty range check (see above).
More on using the Case property
The Case property often acts more like method than a property since it can perform actions beyond just changing a value like a paragraph style or font formatting. Assigning one of the relevant Case constants can cause it to cycle through all words in the sentence or range. Moreover, when setting the wdTitleSentence Case value, the property seems to understand when the range is inside a sentence even when we use it without the entire sentence being selected. That is, if we assign wdTitleSentence to the Case property of a word range somewhere inside the sentence, it will not capitalize the word.
This behavior isn't a problem, but we should understand it to properly use the Case property.
A small disadvantage of using the Case property for capitalization is Word does not understand some words like TrimCharacters (it will catch some but not all special words). In this example, it would convert the uppercase "C" in the middle of the word to a lowercase "c". Such words occur much less often at the beginning of a sentence, particularly in novels, so it's a reasonable compromise.
Final macros
Now we get to the final macros. These macros show how just getting the details right can sometimes make the steps stretch more than we might prefer; however, we just build it one step at a time and enjoy the result. To keep the length down some, these macros use the quote character constants defined in a separate article.
Deleting to the end of a sentence
We focused on deleting to the end of a sentence. Putting all the steps together, we get:
I originally assigned my implementation to Alt+Delete in Word for Windows or Option+Control+Delete on a Mac, but I have tried some variations on Mac since it is a commonly used macro.
Deleting to the start of a sentence
The sibling macro to delete to the start of a sentence is:
For this version, we swapped out EndOf for StartOf at the beginning. In the middle, the trimmed characters and direction are different, and we removed the line that restores the trailing selection spaces. At the end, we added a step to capitalize the new first word of the sentence just after the range is deleted.
I assigned this macro to Option+Delete in Word for Mac or Alt+Backspace on Windows. Unfortunately, some asymmetry exists between my shortcuts, but MacOS does not like to interpret the (forward) Delete key when used with modifier keys. The Mac Delete key is equivalent to the Windows Backspace key.
Use global quote constants
The quotes are defined as global constants for all macros, but if you chose not to use them, just copy the below variable definitions before the line where the trimmed characters are assigned (or at the top of the macro works just as well).
These definitions were explained earlier. These are technically variables not constants, but the trim characters line just uses them as is. What you cannot do is have these variable declarations with the same named constants defined at the module level.
Improvements or extensions
What could we do to make these macros even better? Do any trivial modifications exist that will enhance our editing capabilities?
Undo records
For the second macro, we could encapsulate the changes into an undo record, so the undo shortcut can be used just once to reverse both changes in the document. This is more of a user-friendly tweak for this macro since there are only two changes at most, but it's a nice touch. However, please read the tutorial carefully because undo records can also cause significant problems if not used correctly.
What about paragraphs?
Working through the macro, it's easy to change out the sentence manipulation for a paragraph constant. I don't need the paragraph version as often, but it has come in handy a few times. Given that it requires a tiny expenditure of effort, it's an excellent extension of the base macro.
Delete with a sentence Unit?
Could we trivialize the range extension portion of the macro using just the Delete method?
If you've used Command+Delete (Mac) or Control+Delete (Windows) to delete words, you might remember it also deletes partial words if the insertion point is already in the middle of a word. Well … the Delete method actually has a Unit parameter also, so couldn't we just use a wdSentence Unit with it and mimic that delete behavior with words?
Uhhh … sounds good at first, but nope.
We can't actually use a sentence unit with the Delete method presumably because the standard delete action does not understand what to do with a sentence like it does with a word. Apparently, that's our job. Fortunately, doing so allows us to tweak the behavior to intuitively handle punctuation for us.