Advent Day 10 Ms Access Gurus

VBA > Function > Get Nth Word

Get the Nth word in a string. Useful if you have a code where different parts have a meaning. You can also use this in a query to get a list of all words used in the values of a field (see More Notes).

Screen shot

You can use this function to parse codes and find words.

This VBA can run from Access ... or Excel, Word, PowerPoint, Project, Visio, ... or other Microsoft Office VBA interface. There is nothing in it that requires Access. It is pure VBA!

Examples:


Get the 3rd part of the code, where parts are separated with dashes, and convert to a date:

CDate(GetNthWord("Shed-01-181127-ABC123",3,"-")) = 11/27/2018

The 3rd part of this code is the manufacture date, but it is not in a format that can be directly converted to a date data type, so it is reported as a string:

GetNthWord("Shed-01-27Nov2018-ABC123",3,"-") = "27Nov2018"

Logic

Set up an error handler that exits the function and returns the default value if there is a problem. Dimension vaiables for the number of words and a string for the word that is found.

Flags affect manipulation of the string before it is separated. If you are writing all words to a table, and don't care which position they are in, then you will want to set Flags to break words in more places. If space is being used as a delimiter, then the string is the Trimmed for leading and trailing spaces, and repeating internal spaces are removed.

The string is then split into words, using space to delimit (unless something else is specified by psDeli), and the Nth word is returned.

The number of words is iWordCount, and is 1 plus the upper bound (UBound) of the array. Array indexing starts at 0, so 1 is subtracted to get the Nth word.

The Nth word is returned.

Parameters

Optional:

Code


'*************** Code Start *****************************************************
' Purpose  : Get the Nth Word in a string
' Author   : crystal (strive4peace) 
' Return   : String
' License  : below code
' Code List: www.MsAccessGurus.com/code.htm
'--------------------------------------------------------------------------------

' GetNthWord

'--------------------------------------------------------------------------------
Function GetNthWord( pString As Variant _ , Optional pWordNum As Integer = 1 _ , Optional psDeli As String = " " _ , Optional pBooHasFlags As Integer = 1 _ , Optional pFlagParentheses As String = 1 _ , Optional pFlagComma As Integer = 1 _ , Optional pFlagPeriod As Integer = 1 _ , Optional pFlagDash As Integer = 0 _ ) As String ' s4p 161005, 181207 On Error GoTo proc_err Dim i As Integer _ , iWordCount As Integer _ , sWord As String Dim aWord() As String 'initialize return value GetNthWord = "" If IsNull(pString) Then Exit Function '--------------- Flags If pBooHasFlags <> False Then 'parentheses If pFlagParentheses = 1 Then pString = Replace(pString, "(", " ( ") pString = Replace(pString, ")", " ) ") ElseIf pFlagParentheses = 2 Then pString = Replace(pString, "(", " ") pString = Replace(pString, ")", " ") End If 'comma If pFlagComma = 1 Then pString = Replace(pString, ",", " , ") ElseIf pFlagComma = 2 Then pString = Replace(pString, ",", " ") End If 'period If pFlagPeriod = 1 Then pString = Replace(pString, ".", " . ") ElseIf pFlagPeriod = 2 Then pString = Replace(pString, ".", " ") End If 'dash If pFlagDash = 1 Then pString = Replace(pString, "-", " - ") ElseIf pFlagDash = 2 Then pString = Replace(pString, "-", " ") End If End If '--------------- remove extra spaces If psDeli = " " Then pString = Trim(pString) Do While InStr(pString, " ") > 0 pString = Replace(pString, " ", " ") Loop End If '--------------- parse 'convert string to an array aWord = Split(CStr(pString), psDeli) iWordCount = UBound(aWord) + 1 'array starts at 0 If pWordNum < 1 Or pWordNum > iWordCount Then Exit Function End If '--------------- calculate (array starts at 0) sWord = aWord(pWordNum - 1) '--------------- set return value GetNthWord = sWord Proc_Exit: On Error Resume Next Exit Function Proc_Err: Resume Proc_Exit End Function ' ' LICENSE ' You may freely use and share this code ' provided this license notice and comment lines are not changed; ' code may be modified provided you clearly note your changes. ' You may not sell this code alone, or as part of a collection, ' without my handwritten permission. ' All ownership rights reserved. Use at your own risk. ' ~ crystal (strive4peace) www.MsAccessGurus.com '*************** Code End ******************************************************* '--------------------------------------------------------------------------------

' testGetNthWord

'--------------------------------------------------------------------------------
Sub testGetNthWord() '181210 s4p ' test GetNthWord -- write each word to Debug window Dim sString As String _ , sWord As String _ , i As Integer _ , iCountEmpty As Integer sString = "Joe Smith bought a small shed (Shed-01)," _ & " but then changed his mind and decided to exchange it" _ & " for Shed-02 before delivery was made." i = 1 iCountEmpty = 0 Debug.Print "*** " & Now Debug.Print sString Do 'get the next word, delimiter is space (default, ' True = Has Flags -- take defaults to separate () and , sWord = GetNthWord(sString, i, , True) Debug.Print Space(2) & Format(i, "#,#00. ") & sWord If sWord = "" Then iCountEmpty = iCountEmpty + 1 Else iCountEmpty = 0 End If i = i + 1 'loop until it is probably done Loop Until iCountEmpty = 5 MsgBox "press Ctrl-G to open Debug window", , "Done" End Sub

More Notes

Make a Query

Rather than creating code to run this, you can use this function in the calculated field of a query. You just need a table to make the numbers.

Numbers table

Make a table called Numberz with a Long Integer primary key field called Num. Put as many records in as you think you will need. For this example, we use 20 for the maximum number of words on a line.

If you are using a Numberz table to control number of copies to print, then 3 or 4 records is probably okay. If you are using the Numberz table to make dates, then you'll need at least 31 if you are constructing from parts, and more if you are also using it to create more than a month of days in a range of dates.

Numbers Table

Source table

We have a table of addresses, called c_Address. We will split Addr1, which is the first address line, and might look something like "123 Main Street".

Make a Query

Make a query using whatever table has the field you want to split into words.

In our example using addresses, perhaps it is desired to isolate Street Names so they can be put into a quick-pick table. The street name is between the number and street type, and may be more than one word.

So lets say you have this SQL:

               SELECT MyTable.Addr1 AS MyString
                  , Numberz.Num, GetNthWord([Addr1]
                  ,[num]) AS Wrd, MyTable.AdrID
               FROM c_Address AS MyTable, Numberz
               WHERE ( ( MyTable.Addr1 Is Not Null) 
                  AND ( Numberz.Num <=10) 
                  AND ( GetNthWord([Addr1],[num] ) <>"") )
                  ;

Here are the results, using our example: Get words using a query that calls GetNthWord

Then make another query, on top pf that, to group and count the words:

            SELECT qParse.Wrd
               , Count(qParse.Wrd) AS CountOfWrd
            FROM w_qParse2Words_Add1 AS qParse
            GROUP BY qParse.Wrd
            ;

Scrolling down to somewhere in the S's, here are the results: report and count all words used in a field of a table

If you are parsing to separate address into its discreet types, then you would also have a StreetTypes table to recognize common types like Street, Avenue, Boulevard, and their abbreviations.

Cartesian Query

A cartesian query does not specify how tables are linked so it gets every combination possible ... so you will have a resulting record set with many! more rows than you started with.

Developers

Unlike the text VBA code, that checks for, like 5, blank lines in a row to stop; in a query, you can't do this -- so make optimize to make the number of words to look for equal to the maximum you think you will have, plus a few more.

Beginners

Don't let the apparent complexity of this scare you off from trying it! Spend an hour -- you'll get it!

  1. Create a general module
  2. , paste the code at the bottom
  3. , from the menu bar, choose: Debug > Compile Database
  4. and then Save.

When prompted for a name, use mod_GetNthWord or something else logical that is different than any procedure name. Once it compiles without any issues, you are ready to run.

* if you have problems, email me. I will try to help and then expand these instructions.

Run

Once you have saved this code in a module, to run this, modify testGetNthWord -- then rename it and run it. HOWEVER, you will probably find the query example more useful -- it takes a little longer to set up because you have to create a Numberz table too -- but so worth it!

Reference

Docs / Office VBA Reference / Language Reference / Concepts / Visual Basic / Use Do...Loop statements

Help: Using Do...Loop Statements

Download

GetNthWord_s4p.zip (50 kb, unzips to an Access ACCDB database file for personal use)  

Sample database has:

Share

Share with others ... here's the link to copy:
https://MsAccessGurus.com/VBA/Code/Fx_GetNthWord.htm