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

Parsing a command phrase in a Dragon Professional script

Word • Macros • Dragon • Voice Commands
Peter Ronhovde
34
min read

Creating natural language voice command scripts in Dragon Professional allows more freedom in how commands are stated meaning we can focus more on our writing than remembering precise command phrasings. One approach to parsing a command phrase is to identify relevant keywords. In VBA, a simple technique toward that end uses search patterns with the Like operator. Similar keywords will appear repeatedly in commands regarding identification of relevant document elements, direction, and/or location; so the overall process will benefit from creating functions to identify these types of keywords.

Thanks for your interest

This content is part of a paid plan.

Parsing a command phrase in a custom Dragon Professional script

Parsing a voice command roughly involves several steps:

  • Identify any relevant keywords
  • Set any relevant macro parameters based on the keywords (upcoming)
  • Select and run intended Word VBA macro (upcoming but see also this previous article to get started)

Of course, this is a simplified set of steps, but the implementation isn’t far removed from this idealization. This article will focus on several functions to accomplish the first step. See the links for related articles on the following two steps.

Using keywords is a simple form of parsing text to act on the instruction. There are better ways to interpret command text, but for simple phrases such as with voice commands consisting of only a few words used to manipulate document content, we can still accomplish a lot with this simpler approach.

How do I search thee? Let me count the ways …

There are three main ways to search text in VBA.  Let’s start by saying what we’re not using today.

Not using Word Find in VBA

Microsoft Word’s Find property in VBA is part of the Selection object or any general Range variable. It implements the Find and Replace feature of Word in VBA. While it provides a powerful way to search Word document text, it does not apply to plain text variables without some awkward workarounds.

Nope on the In-String function also

The InStr(…) function searches a string for specific text. The function name is literally an abbreviation for “in string.” It gives the position of the desired text in a string, but it only matches specific text. No wildcards or other pattern-like searches are allowed. While it would work for our current simple parsing tasks, these features make it difficult to use when identifying spoken numbers in a command phrase. There is a workaround for numbers, but the command also reads a little more cryptically than searches using Like.

Avoiding regular expressions for now

Regular expressions (regex) allow detailed search patterns. The syntax often requires some time and testing to get right, but regex searches are powerful. Covering regular expressions is outside the scope of this article series, but if you’re interested in jumping right into probably the best approach, see this previous article for a brief introduction to setting up regex searches in VBA. However, the overall process is more involved than using command keywords. We will tackle parsing commands using regex in an upcoming article.

Today’s winner … the Like operator

In terms of simplicity, the Like operator is the probably the easiest search method. As far as available features, it falls somewhere in between using the InStr(…) function and regular expressions.

It’s an “operator” because it takes two inputs and gives a result. It’s similar to using a plus + sign with numbers (such as 1 + 2 = 3), but Like works with a text variable and a search pattern both of which are plain text strings.

Like returns a True-False (Boolean) result which we can immediately use in conditional statements to make decisions in our script.

Using Like in text searches

Like is clean and clear to read. It further allows some flexibility with wildcard characters to match varied text patterns, but it’s not as detailed as regex. Given Like's flexibility and relative simplicity, it is easier to use in many cases.

Use of keywords

We’re not enforcing a strict word order which is the point of a natural language command. These commands are relatively simple, so the relevant keywords are all we need to properly interpret the command meaning.

What is a plain text string?

Plain text is just the character content without any Microsoft Word or rich text formatting. They are almost always called “strings” in programming. Historically, this probably derived from the literal idea of connecting a string of characters together. We define a string in VBA using double quotes and often store them in “String” variables in VBA.

In VBA, a String is a “value type” akin to a number. A string is not a composite object with individual bits of data or related functions (range variables, for example, consist of data properties as well as various actions called methods that can act on that data or the document). The classification is a little muddled when using strings as arguments for functions, but that is the gist.

Store a plain text command phrase

We need some plain text to search which is usually stored in a String variable. We’ll call our variable SomeText for now.

Dim SomeText As String
' Store text in the SomeText variable
SomeText = "This is a command to do something in Word."

Remember Dim is used in VBA to declare variables with specific data types. We assign plain text in double quotes to the variable using an equals sign = just like with regular numbers.

Basic form with Like

The basic form when using Like is:

SomeText Like "*paragraph*"

We give the variable first, the Like VBA reserved word (meaning we can’t declare a VBA variable named Like), and lastly the plain text match pattern in double quotes.

Like statement result

The result of a Like statement is a True-False (Boolean) value which we can use in conditional statements to make decisions in the script (see previous article for a brief introduction). The above example statement is True if the text “paragraph” appears anywhere in the SomeText variable text.

Like with search pattern variables

The search pattern could also be another String variable which we assign like any other string variable.

Dim SomeMatchPattern As String
SomeMatchPattern = "*paragraph*"
SomeText Like SomeMatchPattern ' Not used for this function

However, in this article, we’ll be giving our search patterns explicitly with the Like statement as in the first example.

Wildcard characters

Each asterisk “*” in the search pattern above is a wildcard character that matches zero or more of any characters in its place—specifically before or after the word “paragraph”. In this case, we’re asking Like to look for the literal text “paragraph” in the SomeText variable while allowing any characters before or after it.

Be careful with search patterns

Valid matches can get a little tricky sometimes since leaving out either asterisk "*" changes the meaning of the search pattern. For example, this search pattern "paragraph*" looks basically the same …

SomeText = "This is my paragraph."
SomeText Like "paragraph*" ' Is False (does not match SomeText)

This gives a result of False because the pattern does not match SomeText.

Huh?

Since this revised pattern omits the first "*", Like attempts to match the text "paragraph" but only when found at the beginning of the SomeText variable. That is, the search pattern indicates that we do not allow any characters to exist before "paragraph" in the string text. Conversely, leaving out the second asterisk in the search pattern as in "*paragraph" requires the "paragraph" text to be found at the end of the SomeText variable string.

Other wildcard characters (not used here)

Other possible wildcard characters for Like statements that are not used in this article include:

  • A question mark ? indicates a single optional character (0 or 1 character) in that location of the pattern. If you are familiar with regular expression search patterns, a ? works differently there.
  • A hashtag symbol # matches a single numerical digit in its pattern location. The digit is required to be present, so “##” requires a two-digit number. For example, “1” would not match the pattern “##”, but “23” would.

An upcoming article will cover a separate function to identify number keywords in a voice command phrase when using Like. If you need more specific or varied match criteria, look into regular expressions.

Using Like in conditional statements

We will repeatedly need a way to identify keywords in a command phrase and then store any respective result in another variable. Toward this end, we set up a VBA conditional statement in the form:

If some match condition is True Then
' Do these steps if a match is found ...
End If

See this previous article for a brief review of conditional statements in VBA. We can use a Like statement as our condition since it returns a True or False result:

If SomeText Like "*paragraph*" Then
' Do these steps if "paragraph" is anywhere in SomeText ...
End If

Like only tells us whether a match was found, so we need to manually store any needed result corresponding to the match inside the If statement.

Plural (and other) forms

This search includes standard plural word forms like “paragraphs” because it contains the singular form. For example, this is not necessary.

' This is not necessary ...
If SomeText Like "*paragraph*" Or SomeText Like "*paragraphs*" Then
' Do these steps ...
End If

We’ll talk more about compound conditions in the next article, but the “*” at the end of the first search pattern catches the extra “s” in the plural form “paragraphs” automatically. Of course, if the plural form of a different word does not use the standard pluralization rule, then you would need to be more careful.

Detect which condition is True using ElseIf

If there are several important keywords, we need to distinguish between them. Once we know which match was found, we can take any necessary actions. One approach is to chain the necessary conditional matches together using ElseIf statements.

An ElseIf statement is basically a continued If statement. How you use it depends on the context.

If match condition one is True Then
' Do these steps if match one is found ...
ElseIf match condition two is True Then
' Do these steps if match two is found ...
'
' Include more ElseIf conditions for any other matches ...
'
Else
' Do these steps if no match above was found ...
End If

Briefly, each ElseIf tests the condition and runs the code below the statement if the condition is True. If the current condition is False, it checks the next ElseIf statement until none are left. After any match is found, the overall If statement is ended. If no matches are found, then the steps under Else are run. Otherwise, nothing happens.

Getting the stated document element

Our first example of command parsing is to determine any document element stated in the spoken command. We expect matches for “paragraph”, “sentence”, “heading”, "word", and others; so we need to define two working variables.

Stored command phrase variable

In an upcoming article, we’ll cover how to access the spoken voice command phrase in Dragon Professional, but for now we’ll work with it as if it is already stored in a plain text String variable named sPhrase.

Dim sPhrase As String

Document element variable

We mentioned earlier that Like searches only tell us if a match was found, so we’ll need to store the intended document element corresponding to the found match manually. We’ll call the result variable sElement which will contain the type of document element the user stated in the command.

Dim sElement As String

Store stated document element

To discern which document element was stated in the sPhrase command, we’ll chain several ElseIf statements together using a series of sequential Like comparisons. Then inside each if statement, we’ll store the respective document element in sElement as a plain text value.

If sPhrase Like "*paragraph*" Then
sElement = "paragraph"
ElseIf sPhrase Like "*sentence*" Then
sElement = "sentence"
ElseIf sPhrase Like "*heading content*" Then
' Needs to be checked before heading
sElement = "heading content"
ElseIf sPhrase Like "*heading*" Then
sElement = "heading"
'
' Include more ElseIf conditions for any other element matches ...
'
Else
' Neither match was found
sElement = ""
End If

In a later article, we’ll use the identified element to run a specific Word macro. We cannot use a Select Case statement to accomplish the same element assignment because Like results in a True-False Boolean value rather than providing the specific matched text (regex does the latter).

Heading content case

The “heading content” keywords need to be checked before the simpler keyword “heading”. The first True result in an ElseIf chain is chosen, so any following conditions are ignored and skipped. Thus, if the search pattern “*heading*” were checked first, “heading content” would never be identified, because “*heading*” would result in a match.

But this is messy …

Unfortunately, copying this long If-ElseIf chain to every macro would be bulky and awkward. Since we’re doing the same checks over and over in related natural language commands, it is convenient and smart to extract the related steps and place them inside a function. Then we can just “call” the function and give it (called “passing”) the voice command phrase to parse. Afterward, we just store the result in the sElement variable.

Function Skeleton

Most of our keyword parsing functions are similar in structure, so we’ll use the following function skeleton:

Function GetPhraseElement(sPhrase As String) As String
' Include steps to pick the correct document element ...
' Assign a returned document element result ...
End Function

Of course, each keyword identification function below will have it’s own unique name corresponding to the information it’s parsing from the command phrase.

What parameter?

Each function receives the command phrase as a string variable sPhrase.

sPhrase As String

I like to precede string variable names with an “s” to remind myself what type of data the variable stores. See the extension below where we include an additional default value parameter.

Return result

Since we’re encapsulating the parsing process inside a function, we no longer assign the sElement variable directly as we did above. We instead assign the result as the return value of the function. That is, we assign the return value to the function name anywhere inside the function.

GetPhraseElement = "SomeElement" ' Use appropriate result

If we do not find a match in the given phrase, then we return an empty string “” for simplicity.

GetPhraseElement = "" ' Nothing was found

See the extended content below with an improvement for a customizable default value.

Element phrase function

We use almost the same conditional statement as above with the chain of ElseIf statements. We’re just assigning the matched result to the function name instead. The function to parse the document element from the command phrase is:

Function GetPhraseElement(sPhrase) As String
' Check given phrase for element keywords (paragraph, sentence, etc.)
' Plural forms are automatically included by default
' Returned values are respective Word document elements
' or an empty string "" if no match was found

' Determine if an element keyword exists in sPhrase
If sPhrase Like "*sentence*" Then
GetPhraseElement = "sentence"
ElseIf sPhrase Like "*paragraph*" Then
GetPhraseElement = "paragraph"
ElseIf sPhrase Like "*heading content*" Then
' Must be before the heading check
GetPhraseElement = "heading content"
ElseIf sPhrase Like "*heading*" Then
GetPhraseElement = "heading"
ElseIf sPhrase Like "*word*" Then
GetPhraseElement = "word"
ElseIf sPhrase Like "*character*" Then
GetPhraseElement = "character"
Else
' Empty string indicates no match found
GetPhraseElement = ""
End If
End Function

Given the structure of the long If statement, we are guaranteed something is assigned as the returned value even if it is only an empty string "".

Using the function result

When using the function in a main voice command script, we’ll store the function result in the sElement variable:

sElement = GetPhraseElement(sPhrase)

After this step, you use sElement as needed in the main script. Nice and tidy.

Benefits of functions

The nice thing about this version is we can reuse the function in any voice command script. Using separate functions also allows us to mix and match them to create other more complex voice commands.

A small disadvantage of creating these functions is they make detailed customization a little more trouble. For example, if you wanted to exclude the document element “word” from a particular script, you can’t without modifying the function which half defeats the point of creating it. You would need to work around the excluded case within the main script.

No Dragon Professional library

On the other hand, we still run into an issue with Dragon Professional not allowing a local library of functions. We would need to use an external file for any common code, but as far as my research indicates, Dragon Professional scripts are interpreted meaning the file would be loaded every time you give a voice command.

Ummm … bad.

Dragon’s presumption seems to be that every script should be independent. I understand the intention, but it makes for clunky scripts. Including a customizable script/function library would be simple and make creating better, cleaner scripts much easier.

Improved element phrase function

The above element identification function is fully functional, but what if someone (probably you sometime later) wants the default to be a paragraph element? Or what if you change the default value a lot between command scripts?

Since the default value in the above function is an empty plain text string “”, we could test the result from the function and just change it manually.

' Get any stated document element from command phrase
sElement = GetPhraseElement(sPhrase)

' Check and reset the default value ...
If sElement = "" Then sElement = "paragraph"

That’s not bad, but it would be convenient if the function handled this for us since it’s probably a relatively common task. Plus, it’s just cleaner to be able to exclude the extra steps.

Optional default value

With that in mind, I prefer to structure my function to include a default value as a second parameter. The new function skeleton is:

Function GetPhraseElement(sPhrase As String, Optional SDefault As String = "") As String
' Include steps to pick the correct element ...
' Assign a returned document element result ...
End Function
Optional parameter

The second parameter is preceded by the reserved word Optional which literally tells VBA the parameter is not required. We still give a data type As String since we plan to use it as a default return value which is also a String.

Optional SDefault As String ' Not quite done
Default optional parameter value

Since we are not required to give the parameter when we use the function, we should specify a default value. That is the = “” part of the statement.

Optional SDefault As String = ""

Whatever argument is passed for SDefault must be a String. If the user doesn’t give a second argument, VBA assumed SDefault was an empty string “” inside the function.

What changes?

The only other change to the function content is in the Else part of the conditional statement.

' ... prior part of If statement
Else
' No match found, so assign default value
GetPhraseElement = SDefault
End If

If no prior matches were found, this step assigns the default returned value as SDefault. If SDefault wasn’t given, it is assumed to be an empty string “”, so it behaves like the original function.

Improved function

Almost everything in the function is the same as before.

Function GetPhraseElement(sPhrase As String, Optional SDefault As String = "") As String
' Check given phrase for element keywords (paragraph, sentence, etc.)
' Plural forms are automatically included by default
' Returned values are respective Word document elements
' or SDefault if no match is found

' Determine if an element keyword exists in sPhrase
If sPhrase Like "*sentence*" Then
GetPhraseElement = "sentence"
ElseIf sPhrase Like "*paragraph*" Then
GetPhraseElement = "paragraph"
ElseIf sPhrase Like "*heading content*" Then
' Must be before the heading check
GetPhraseElement = "heading content"
ElseIf sPhrase Like "*heading*" Then
GetPhraseElement = "heading"
ElseIf sPhrase Like "*word*" Then
GetPhraseElement = "word"
ElseIf sPhrase Like "*character*" Then
GetPhraseElement = "character"
Else
' No match found, so use default value
GetPhraseElement = SDefault
End If
End Function

Now we have a convenient way to change the default document element.

Example uses

With this version of the function, we keep the same functionality as before by just omitting the second argument (a parameter provided by the user).

sElement = GetPhraseElement(sPhrase)

If no match is found, sElement will still be an empty string “” because that is the default value of SDefault.

If we wanted to change the default value for a given function call, we could use:

sElement = GetPhraseElement(sPhrase, "paragraph")

If the function cannot find an explicit element match in the command phrase, it now defaults to “paragraph”, but we could also easily change that value in the next script if we needed to do so. This variation allows us to skip manually checking for a missing element to set a different default value. It’s clean and concise.

Advantages of using Like

Like provides a simple approach to creating more natural voice commands by focusing on command keywords. We don’t get everything we want, but it’s easy to set up, and it allows more freedom in the command phrasing than using just Dragon Professional list variables in the custom commands.

Like is useful in simpler cases, and it’s a nice starting point for some easy custom natural language commands.

Disadvantages of using Like

Like does have it’s shortcomings though.

Can be awkward if there are many options

Like can be tedious when identifying numbers in text. The matches can stretch out where the result can be clunky and awkward to read. This partially defeats the “clean” notation of the command.

For me, this is enough motivation to switch over to using regular expressions, but that’s for another day.

Like result is either True or False

We don’t get any other information with Like other than whether our text variable matches the given search pattern or not. We must use a dedicated If statement for each word group if we want to match specific words.

Order information is lost

We lose any ordering information that list variables provide in a Dragon Professional script. For example, knowing the order is useful if we want a macro that works with two different types of document elements.

Some ordering information could be recovered by using InStr(…) after a verified match since it returns a position in the text, but beyond a few simple choices, you might as well adopt regular expressions.

Gotchas

What could go wrong?

Overlapped English word meanings

We still have to watch out for some tricky phrasings. For example, a human would have no problem with this command.

"Select to the third paragraph above this one"

It’s wordy and a little convoluted as stated, but this is just an example of possible command confusion. A simple parse attempt will not be able to distinguish between the meanings of the words “third” and “one”. The script doesn’t really understand the command. It’s just matching keywords.

If you want to allow this type of phrasing (I did using regex), you would need to include an additional check or two to clarify the command. It’s possible to use Like to distinguish between the different number forms in the same command, but the additional required matches make it more awkward.

Getting the Direction

Earlier, we interpreted the document element from a voice command, so what about a stated direction?

We could specify a direction in multiple ways:

"Select back to the previous paragraph"
"Select up one paragraph"
"Select forward three words"
"Select to the third paragraph below"
"Select over to the next sentence"

We’re not focused on the phrasing variations at this moment (see upcoming article for more discussion on that topic), and we’ll also get to parsing the numbers in a separate article, but each of these commands has an explicit direction: “back”, “up”, “forward”, “below”, or “right”. "Next" is an implied direction of "forward".

Direction words

Related direction keywords not used above include: “backward”, “down”, “above”, or “left”.

Implied direction from position words

Other words that are related to direction based on an implied document element position include: “previous”, “next”, “last”, “first”, “start”, “end”, and so forth. The word “over” is ambiguous, but it might be interpreted to also mean “forward”.

In this function, we’re blurring the distinction between position and direction because a given document position usually has an implied direction associated with it relative to the working position in the document.

Direction variable

Let’s put the above keywords into an extended If-ElseIf statement like we did with the document elements above. We’ll store the resulting direction in a plain text variable sDirection.

Dim sDirection As String

As previously mentioned, I like to precede string variables with an “s” to remind myself what type of data the variable stores.

Forward matches?

For this interpretation forward, right, down, below, and next all indicate the same direction—forward in the document. We’ll condense these all to a single keyword direction “forward”.

Similar to what we did for document elements, our search patterns are: “*forward*”, “*right*”, … “*next*”. Combining these with the Like operator, we have:

sPhrase Like "*forward*"
sPhrase Like "*right*"
' with the others ...

Any of these keywords correspond to the same direction. In conditional statements, this corresponds to an Or operator since A Or B gives a True result if either A or B is True. See this previous article for a brief review of conditional statements in VBA.

With that in mind, we combine all these Like searches using Or’s.

If sPhrase Like "*forward*" Or sPhrase Like "*right*" Or sPhrase Like "*down*" Or _
sPhrase Like "*below*" Or sPhrase Like "*next*" Then
sDirection = "forward"
End If

This is a long line, so we used the line continuation character underscore _ to make it easier to read.

Backward matches?

All the other direction words correspond to “backward” direction, so we insert an ElseIf condition.

sPhrase Like "*back*" ' also catches backward
sPhrase Like "*left*"
' with the others ...

Again, we need to combine each search into a series using Or’s because any of these keywords correspond to a backward direction in the document.

' ... forward part of if statement
' Now include backward direction checks
ElseIf sPhrase Like "*back*" Or sPhrase Like "*left*" Or sPhrase Like "*above*" Or _
sPhrase Like "*up*" Or sPhrase Like "*previous*" Then
sDirection = "backward"
End If

These matches are only checked if the “forward” matches fail.

The search pattern “*back*” also catches “backward” if it is used in the voice command.

No direction matches?

If no match is found, we’ll assign a default string named SDefault (see above for the optional parameter). This would happen on any other situation which corresponds to an Else part of the overall If statement.

' ... previous parts of the If statement
Else
' No match found, so assign SDefault string
sDirection = SDefault
End If

A default direction might be forward, but I sometimes prefer to leave it unspecified. The default value will be set by the Optional function parameter (see above for the element version).

Direction conditional statement

Putting all this together, the resulting direction conditional statement is:

If sPhrase Like "*forward*" Or sPhrase Like "*right*" Or sPhrase Like "*below*" Or _
sPhrase Like "*down*" Or sPhrase Like "*next*" Then
sDirection = "forward"
ElseIf sPhrase Like "*back*" Or sPhrase Like "*left*" Or sPhrase Like "*above*" Or _
sPhrase Like "*up*" Or sPhrase Like "*previous*" Then
sDirection = "backward"
Else
' No match found, so assign SDefault string
sDirection = SDefault
End If

All the above word options give us quite a bit of flexibility in the command wording when interpreting a stated direction in the command. We’ll connect this direction assessment to a macro choice in a later article.

See below for the full function, so we don’t duplicate as much content.

Alternative default direction (not used)

Depending on your use case(s), it may be convenient to have a simpler default direction.

' Alternative version using forward as the default
If sPhrase Like "*back*" Or sPhrase Like "*left*" Or sPhrase Like "*above*" Or _
sPhrase Like "*up*" Or sPhrase Like "*previous*" Then
sDirection = "backward"
Else
' Anything else including no match found
sDirection = "forward"
End If

This is probably the easiest approach overall since we only need to check the backward direction, but I like testing for the explicit "forward" and "backward" matches since they allow us to detect whether any direction keyword was given in the command.

Getting the location

Location and direction are related when you’re working in a document, but some commands may require the distinction. For example, we may wish to select all text to the start or end of the current heading, so we need a way to specify that in the command.

Declare location variable

Since we’ve already constructed the direction conditions earlier, let’s just outline the location conditions here. First, we declare a new location variable sLocation.

Dim sLocation As String

The intention is to keep track of whether a command is to the beginning or end of whatever document element is given.

Location keywords

Words corresponding to the beginning include: “beginning”, “start”, “top”. Similarly, words corresponding to the ending include: “ending”, “end”, “bottom”.

Keywords “next” or “previous” also imply a relative position in the document. For all of my current use cases, they are synonymous with the direction in the document, so I omit them here.

Location conditional statement

Since we’ve constructed the conditional statement twice already, let’s jump into it. Following the earlier patterns, our conditional statement to determine the location is:

If sPhrase Like "*begin*" Or sPhrase Like "*start*" Or sPhrase Like "*top*" Then
sLocation = "start"
ElseIf sPhrase Like "*end*" Or sPhrase Like "*bottom*" Then
sLocation = "end"
Else
' No match found, so use empty string
sLocation = SDefault
End If

The pattern “*begin*” also catches any use of “beginning” in the command, and “*end*” matches “ending”.

The default value will be set by the Optional function parameter (see above for the element version).

Phrase parsing functions

The above conditional statements are long if we include all of them in every custom script, so it’s useful to split them up into separate functions. This will allow us to condense the voice command script and make it easier to read.

In principle, encapsulating them into separate functions also allows us to more easily make changes that work for all scripts, but Dragon Professional advanced scripting lacks of a local function library. Unless you’re willing to load an external file on every invocation of the command, this makes our life harder or at least messier since we need to copy the function to every script in which it is used.

Consistent default value

In each function, the standard default value is an empty string “”, but you could readily add your own default as a second argument in the function call.

Element phrase function

This function parses relevant document elements in the command. This function is repeated from above for completeness.

Function GetPhraseElement(sPhrase As String, Optional SDefault As String = "") As String
' Check given phrase for element keywords (paragraph, sentence, etc.)
' Plural forms are automatically included by default
' SDefault is returned if no match is found

' Determine if an element keyword exists in sPhrase
If sPhrase Like "*sentence*" Then
GetPhraseElement = "sentence"
ElseIf sPhrase Like "*paragraph*" Then
GetPhraseElement = "paragraph"
ElseIf sPhrase Like "*heading content*" Then
' Must be before the heading check
GetPhraseElement = "heading content"
ElseIf sPhrase Like "*heading*" Then
GetPhraseElement = "heading"
ElseIf sPhrase Like "*word*" Then
GetPhraseElement = "word"
ElseIf sPhrase Like "*character*" Then
GetPhraseElement = "character"
Else
' No match found, so use default value
GetPhraseElement = SDefault
End If
End Function

Direction phrase function

This function parses any document direction indicated in the command.

Function GetPhraseDirection(sPhrase As String, Optional SDefault As String = "")As String
' Check given phrase for direction related keywords
' Plural forms are automatically included by default
' SDefault is returned if no match is found

' Determine if a direction related keyword exists in sPhrase
If sPhrase Like "*forward*" Or sPhrase Like "*right*" Or sPhrase Like "*down*" Or _
sPhrase Like "*below*" Or sPhrase Like "*next*" Then
GetPhraseDirection = "forward"
ElseIf sPhrase Like "*back*" Or sPhrase Like "*left*" Or sPhrase Like "*above*" Or _
sPhrase Like "*up*" Or sPhrase Like "*previous*" Then
GetPhraseDirection = "backward"
Else
' No match found, so use default value
GetPhraseDirection = SDefault
End If
End Function

Some overlap exists in the concepts between direction and location. For direction, we’re thinking more about a literal but ambiguous direction not necessarily a specific or relative position in the document. We could choose to extend the direction matches to apply to “start”, “end”, or similar variations; but this version separates the concepts for clarity.

Location phrase function

This function parses any document position indicated in the command which basically includes the start and end of whatever document element is under consideration.

Function GetPhraseLocation(sPhrase As String, Optional SDefault As String = "") As String
' Check given phrase for location keywords
' Plural forms are automatically included by default
' SDefault is returned if no match is found

' Determine if an location related keyword exists in sPhrase
If sPhrase Like "*begin*" Or sPhrase Like "*start*" Or sPhrase Like "*top*" Then
GetPhraseLocation = "start"
ElseIf sPhrase Like "*end*" Or sPhrase Like "*bottom*" Then
GetPhraseLocation = "end"
Else
' No match found, so use default value
GetPhraseLocation = SDefault
End If
End Function

Some overlap exists in the concepts between direction and location. For location, we’re thinking more about a specific position usually relative to the current working position in the document.

Example uses

For completeness, here are some examples of using these functions. We can define all three data variables at once.

Dim sElement As String, sDirection As String, sLocation As String

Data type aside

As a quick aside, we need to explicitly declare each variable in the comma separated list “As String”. If the type is omitted for any of them, they would instead be stored as a Variant type. As such, they could store any value type of data based on how the variable is used. It could cause problems when attempting to pass them to functions, but the assignments below would still work. Variant is essentially a generic data type, so the variable would temporarily be set as a string when the VBA tries to store our function's returned string value in it.

Function calls

Now we call the above functions and store the result in the respective variables.

sElement = GetPhraseElement(sPhrase, "paragraph")
sDirection = GetPhraseDirection(sPhrase, "forward")
sLocation = GetPhraseLocation(sPhrase)

We must include the command sPhrase with each function. For now, we assume this is determined previously in the script (see upcoming article). We can include or exclude a default value by just adding or omitting the second argument (a parameter value provided by the user).

The default values of the document element and the direction are respectively “paragraph” and “forward”. If no match is found for the location, sLocation will default to an empty string “” because that is the default value of SDefault given in the earlier function definition.

We could also easily change the defaults values in another script or even pass a String variable if we needed to do so. It’s clean and concise, making our main script easier to read and understand.

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.