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

Toggle quotes around Range

Word • Macros • Functions
Peter Ronhovde
16
min read

Some actions can be readily applied to multiple document elements all of which might be useful, so this workhorse function inserts or removes double quotes around any given range.

Thanks for your interest

This content is part of a paid plan.

Toggle Quotes around Range

It’s natural to apply double quotes to a paragraph, sentence, or a specific selected range. It’s messy to copy and change a function with only minor changes, or worse, to recreate everything from scratch for each use case.

Why not create a tool we can use for any of them?

In this function, we'll toggle double quotes around a given range rather than a specific document element like a paragraph or sentence.

It would be natural to go ahead and extend it to also work with parentheses or single quotes since toggling those punctuation marks around a range would share almost identical logic. However, we’ll stick with double quotes for this article to keep the commentary more targeted but see the more general version if you prefer to start there since the articles overlap.

Other functions

This function uses a little helper function TrimRange to trim any blank space off both ends of the initial range. Also, the left and right double quotes are different characters in Word for Mac and Windows, so we use another pair of simple functions for them.

What’s the plan?

Digging into the details, how do we detect and then add or remove quotes around a given range?

  • Trim any spaces or paragraph marks off either side of the range (simplifies any later tests).
  • Check whether any double quotes are just outside the range on either side. If so, include them in the range.
  • Test whether double quotes exist on both sides. If so, delete them. If not, add them to both sides or add the missing double quote.

The initial step of trimming the blank space from either side sets up a clear starting condition for the rest of the function. It’s easier to work with a range when we know a regular character is present on either side since there are fewer variations to consider.

What about straight double quotes?

For simplicity, we will not consider straight double quotes as character Chr(34) since I almost never use them in the context of writing a novel or novel notes. If you prefer using straight quotes in Word, it’s not difficult to change the final function to accommodate them, or the generalized function will handle them alone.

What if there are double quotes just outside the given range?

Ahhhh, yeah, little questions like this are inevitable.

This is a bit of a judgement call. On the one hand, should we work outside the given range at all?

A user might argue, “Hey, what are you doing? I gave you that range to work on! What are you doing grabbing something outside it?”

I tend to err on the other side of making a macro or function more convenient to use, so I think the better option is to check for and include any double quotes just outside the given range.

Why?

I think it would be weird to insert a new double quote next to another double quote if it’s just a character outside the given range. Checking only requires a few extra steps in the macro, and it’s easier to manipulate the text if it’s inside the range.

Just be clear what the macro or function does and how it works in the description (add a few comment lines at the top of the macro).

Create the function skeleton

Start by creating the function skeleton.

Function ToggleQuotesRange(rTarget As Range) As Range
' Include function steps ...

' Return modified range
Set ToggleQuotesRange = rTarget ' Temporary
End Function

What parameters to use?

We accept the target range rTarget to trim. This variable is not changed during the function (normal range variables could be changed; see this article on ranges for a brief explanation).

Return type

We return the resulting modified range which we determine by the end of the finished function.

What if we're given an invalid range?

First, what if a macro provides our function an invalid range?

This is usually indicated by a Nothing value for the range or any object variable (see previous article on ranges for more explanation). We add an initial validation check and quit the function if the range isn’t valid.

If rTarget Is Nothing Then
' Invalid range, so let user know and exit ...
End If

The “Is” keyword compares objects in VBA similar to an equals = sign for regular values, and we use “Is Nothing” because Nothing is not an actual value like a 0 or -1.

Return Nothing for invalid range

If we detect and invalid given range, we first Set the return value (via the function name) to Nothing to indicate an invalid result for the function.

Set ToggleQuotesRange = Nothing

Exit Function

Then we exit the function immediately.

Exit Function

Putting it together, we have:

If rTarget Is Nothing Then
' Invalid range, so let user know and exit
Set ToggleQuotesRange = Nothing
Exit Function
End If

After this conditional statement, we at least know the target range is valid.

Create duplicate working range

We want to avoid unintended changes to the rTarget range, so we immediately create a duplicate of it which we call r just to keep the name short.

Dim r As Range
Set r = rTarget.Duplicate

Now our working range r is independent of the given range rTarget, so a user won’t be unpleasantly surprised by the target range being changed during the function.

We needed to declare the range explicitly using a Dim command since we're passing it to a function below. VBA is picky about knowing for sure what the argument type is.

Trim the blank space

Using a previous function, we quickly trim any blank space off either side of the working range.

Set r = TrimRange(r)

We reassign the result back to the working range r. This task is common enough that we created a separate function.

Recall we use "Set" because a range is an object containing more data just a plain value.

Check whether double quotes exist already

We start by checking whether any double quotes exist just outside the range and include them in the range.

Including nearby double quotes just outside the working range is a preference, and some could argue it logically shouldn’t be done that way since the user “specifically” provided the target range. I think including any nearby double quotes makes the function a little more general and convenient to use, but omit these steps if you don’t like them. It won’t affect the rest of the function steps.

Why bother?

Just for convenience and clarity with the following function steps.

After we include any preceding or trailing double quotes outside the working range, we know any existing quotes should be at none, one, or both sides of the working range; so we can make upcoming decisions more easily. See also the gotcha for duplicated double quotes, but we ignore this infrequent possibility here.

Get previous and next characters

We need the previous and next characters before and after the working range.

PreviousCharacter = r.Previous(Unit:=wdCharacter).Text
NextCharacter = r.Next(Unit:=wdCharacter).Text

These methods Previous and Next both return a range outside our working range r corresponding to the previous or next document Unit specified. We indicate wdCharacter here. We then had to access the Text property to get the plain text character.

Assigning the function result to a variable and accessing the Text property both required parentheses to be used around the Unit argument.

If either character just outside the working range is a double quote, we'll extend the range below to include it.

Include left double quote

For the first character of the range, we check whether it is a left double quote. If so, we extend the Start position of the range backward over the character.

If PreviousCharacter = LeftDQ Then
r.MoveStart Count:=-1
End If

The default move Unit is by character, so we don’t need to specify it. The Count option assigned as -1 tells the command to move the Start position backward one unit in the document.

Since we only have one brief command here, we can shorten the conditional statement.

If PreviousCharacter = LeftDQ Then r.MoveStart Count:=-1

It makes the steps a little harder to read, but it helps keep our function cleaner and smaller. I generally prefer this presentation if the steps are clear enough.

The double quote characters use two previous functions LeftDQ and RightDQ (below), respectively, because the character values depend on whether you’re using Word for Mac or Windows.

Include right double quote

For the rightmost character of the range, we check whether it is a right double quote. If so, we extend the End position of the range forward over the character.

If NextCharacter = RightDQ Then
r.MoveEnd
End If

The default move Unit is again by character, and the default Count is by 1 unit, so we don’t need to specify either of them.

Again, we can shorten the conditional statement if we wish.

If NextCharacter = RightDQ Then r.MoveEnd

See this previous article if you would like to review conditional statements.

Check for double quotes

Given the current first or last characters of the range, we have three cases:

  • Double quotes on both sides → delete both of them
  • Double quote only on one side → add the missing double quote
  • No quotes on either side → add double quotes on both sides

Let’s translate these into VBA.

Get first and last characters

For all cases above, we need the first and last characters of the range to do our checking.

FirstCharacter = r.Characters.First.Text
LastCharacter = r.Characters.Last.Text

These commands use the Characters collection of the range. The First or Last references return ranges corresponding to the respective character positions. We finally refer to the Text property to get the actual plain text character which we then store (using the equals = assignments) in the respective variable, FirstCharacter or LastCharacter.

Double quotes on both sides

Similar to the above conditions for the previous and next characters, we check whether the first or last characters are a left or right double quote, respectively.

If FirstCharacter = LeftDQ And LastCharacter = RightDQ Then
' Double quotes on both ends, so delete them ...
End If

In this case, both sides must be double quotes before we delete them, so we use an And operator between the conditions.

Note the “FirstCharacter = SomeCharacter” notation in this conditional statement is actually a condition not an assignment to a variable like above. It is an unfortunate ambiguity in VBA, but we don’t need to think much about it because VBA is able to determine the proper usage by context.

Delete double quotes

To delete the double quotes, we again refer to the ranges returned by the respective First and Last references from the Characters collection. We then refer to the Delete method to delete the two single-character ranges.

r.Characters.First.Delete
r.Characters.Last.Delete

These commands remove them from the document not just the range.

Cannot delete the Text property

Note we are not deleting the “Text” of the range because Text is a property.

r.Characters.First.Text.Delete ' Does not work

This doesn’t work because the Text property of a range has no Delete method. It just represents the string of plain text characters spanned by the range in the document.

Double quotes on one or no sides

There are a few ways to detect and change double quotes on either or both sides of the range. Let’s briefly explore an alternative as practice.

Longer variation

The logic to detect the presence of double quotes on either or both sides can stretch out a little and make the function messier than I prefer.

If FirstCharacter = LeftDQ And LastCharacter = RightDQ Then
' Double quotes on both sides, so delete them
ElseIf FirstCharacter = LeftDQ And Not LastCharacter = RightDQ Then
' Double quote only on left side, so add right one
ElseIf Not FirstCharacter = LeftDQ And LastCharacter = RightDQ Then
' Double quote only on right side, so add left one
Else
' No double quotes, so add both
End If

Ughhh.

We use a Not operator to reverse the True-False (Boolean) value of one of the character comparisons. We could’ve used a not equals <> comparison instead which works fine with strings (two strings being "equal" requires an exact match including any upper or lower case characters). It’s just a preference, but I thought the Not looked better here.

On the plus side, it’s clear and … it works, I suppose, but I don’t like it. It’s just too long for me, so I won’t break it down with any more commentary.

Shorter variation

I went with a shorter solution.

If FirstCharacter = LeftDQ And LastCharacter = RightDQ Then
' Double quotes on both ends, so delete them ...
Else
' No double quotes or only on one side of the range
' Add double quotes to both sides of range ...
End If

I felt like this shorter version was cleaner, but your mileage and preferences may vary.

Left double quote

To add the double quotes to the left side of the range in this version, we check and add it to the side that doesn’t already have one.

If FirstCharacter <> LeftDQ Then
r.InsertBefore Text:=LeftDQ
End If

Recall the <> symbol is “not equal,” so we basically add the left double quote if it doesn’t already exist on the starting (left) side.

InsertBefore inserts the given plain text in the Text option on the left side of the range, and the range automatically extends to include the new text.

Right double quote

Similarly, we can check whether the last character of the range is a right double quote and add one if not.

If LastCharacter <> RightDQ Then
r.InsertAfter Text:=RightDQ
End If

InsertAfter inserts the given plain Text in the option on the right side of the range. The range automatically extends to include the new text.

Independent checks

Notice these conditional statements are not connected. The function checks each condition separately since we don’t know which double quote is missing or if both are needed.

Again, these conditional statements are relatively concise, so we can shorten them if you prefer.

If FirstCharacter <> LeftDQ Then r.InsertBefore Text:=LeftDQ
If LastCharacter <> RightDQ Then r.InsertAfter Text:=RightDQ

Return the modified range

We finally return the working range with any modifications in case the user wants to do anything with it.

Set ToggleQuotesRange = r

In many of my own use cases, I don’t care about the returned range, but it’s good to be more general with a function if it makes sense. It’s also more work to modify the function later if we decide we need the resulting range in some other macro because we would need to work through the logic again perhaps months after finishing it.

Gotchas

Where could all this go wrong?

This function does modify the document, so as a general rule, we should be careful before assuming the function is “done.” Still, it is relatively safe since we’re only adding or removing specific individual characters.

What if an empty range is passed to the function?

We’re assuming this is a valid empty range since we already accounted for an invalid range in the function.

This function just inserts the double quotes around the empty range as normal. The various steps handle it without a problem even when the first or last characters happen to refer to the same character position in the document.

Duplicated double quotes?

We don’t check for duplicated quotes at either side of the range.

This case is unusual enough that it’s a reasonable compromise to not bloat the function by checking and correcting unusual special cases.

Final Function

Putting everything together, the function is:

Function ToggleQuotesRange(rTarget As Range) As Range
' Toggle left and/or right double quotes around given range rTarget
' Return resulting range whether or not it is modified
' Ignores straight double quotes

' Return Nothing if rTarget is invalid
If rTarget Is Nothing Then
Set ToggleQuotesRange = Nothing
Exit Function
End If

' Define a working range independent of rTarget
Dim r As Range
Set r = rTarget.Duplicate

' Trim spaces or paragraph marks from both ends
Set r = TrimRange(r)

' Check for double quotes just outside range and include them if present
PreviousCharacter = r.Previous(Unit:=wdCharacter).Text
NextCharacter = r.Next(Unit:=wdCharacter).Text
If PreviousCharacter = LeftDQ Then r.MoveStart Count:=-1
If NextCharacter = RightDQ Then r.MoveEnd

' Check for left or right double quotes around range
FirstCharacter = r.Characters.First.Text
LastCharacter = r.Characters.Last.Text
If FirstCharacter = LeftDQ And LastCharacter = RightDQ Then
' Delete double quotes from both sides of range
r.Characters.First.Delete
r.Characters.Last.Delete
Else
' No double quotes or only on one side of range
' Add double quotes to both sides of range
If FirstCharacter <> LeftDQ Then r.InsertBefore Text:=LeftDQ
If LastCharacter <> RightDQ Then r.InsertAfter Text:=RightDQ
End If

' Return the possibly modified range
Set ToggleQuotesRange = r
End Function

Another common use case is with parentheses. You could copy this function and change left double quote LeftDQ to open parenthesis “(“ and right double quote RightDQ to close parenthesis “)”, but that would half defeat the point of implementing the function for a range. See the more general version that works with any left and right characters (there is significant overlap in the commentary, but both articles stand on their own).

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.