home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol12n18.zip / FONEWO.DOC < prev    next >
Text File  |  1993-09-28  |  31KB  |  682 lines

  1. FONEWORD.EXE (VERSION 1.0)              Copyright (c) 1993 Neil Rubenking
  2. -------------------------------------------------------------------------
  3.               First Published in PC Magazine October 26, 1993 (Utilities)
  4. -------------------------------------------------------------------------
  5. Create Mnemonic Phone Numbers With FONEWORD
  6.  
  7. BY NEIL J. RUBENKING
  8.  
  9.      Do you tend to forget phone numbers? Can you remember 1-800-COLLECT
  10. more easily than 1-800-265-5328? 
  11.  
  12.     FONEWORD is a Windows 3.1 utility that finds all the mnemonic words
  13. and phrases that can be made from ordinary seven-digit telephone numbers.
  14. It gives you three different sets of possibilities, ranging from perfect
  15. ``vanity numbers'' (BIG SHOT), which consist of nothing but actual words,
  16. to word-plus-number combinations (8 DOLLAR), to a list of all the letter
  17. combinations that correspond to a given phone number. While many telephone
  18. numbers yield no useful mnemonics, it's surprising how many do.
  19.  
  20. DOWNLOADING AND INSTALLATION
  21.  
  22.      FONEWORD is written in Microsoft Visual Basic 3.0, and it uses both
  23. the library file VBRUN300.DLL and a number of .VBX custom control files.
  24. Because it uses VB 3's built-in database functions, it also requires
  25. several additional DLLs for database support.
  26.  
  27.      Because some readers will already have Visual Basic installed on
  28. their systems and others will not, FONEWORD is available in two versions.
  29. If you already have VB Professional Edition 3.0 installed, you need only
  30. the file FONESM.ZIP. Simply download it, unzip it into a subdirectory on
  31. your hard disk, and create a program item (icon) for it in Program Manager.
  32. Otherwise, download the file FONED1.ZIP, unzip it to a floppy disk or a
  33. subdirectory, and run the SETUP program you'll find on that disk or directory.
  34. This SETUP program was created by the Setup Wizard application that comes
  35. with Visual Basic. It installs the necessary support files if they're not
  36. present and updates them if they're present but out of date.
  37.  
  38.      If you want to modify portions of the source code, you'll need Visual
  39. Basic Professional Edition, Version 3.0. (The regular edition lacks some of
  40. the custom controls.)
  41.  
  42. USING FONEWORD
  43.  
  44.      FONEWORD's main screen consists of a text box, three list boxes,
  45. and their associated controls. To use FONEWORD, simply type a phone
  46. number (numeric input only, up to seven digits) into the text box at top
  47. center and press the button labeled ``Only words'' at the top of the left
  48. list box. FONEWORD will consult its database and attempt to find
  49. combinations of words that utilize all of the digits in the number.
  50.  
  51.     Some telephone numbers generate no items for this list, while others
  52. produce dozens. Of course, it's up to you to decide among PIN-DROP, SHOE-POP,
  53. SIN-EROS, and a host of others. (I did not purge the dictionary of all the
  54. terms some people might find offensive.)  Since the digits 0 and 1 have
  55. no letter representations, they are treated as words in their own rights
  56. and so yield combinations such as NUMBER 1.
  57.  
  58.     If the ``Only words'' list produces no suitable vanity numbers, press
  59. the ``Real words'' button above the middle list box. Entries in the middle
  60. list need contain only one real word of two letters or more. Each entry
  61. displays the real word set off by spaces from any unconverted numbers,
  62. such as 7 COME 11.
  63.  
  64.     To list all possible combinations of letters derivable from the phone
  65. number you entered, press the ``All words'' button above the right list
  66. box. With three possible letters for each digit, a full seven-digit phone
  67. number will yield 3 to the power of 7 (2,187) different letter combinations.
  68. The digits 0 and 1 don't correspond to any letters, so if the number
  69. contains any 0s or 1s,  there will be fewer combinations. If you're
  70. willing to accept a vanity number with words misspelled, for example,
  71. KATT-INN for a kennel, you may be able to find one by scrutinizing this
  72. list.
  73.  
  74.     Database lookups are relatively slow operations, so filling the list
  75. boxes can take a few minutes. Immediately to the left of each list box
  76. is a gray bar that gives a visual indication of how much processing is
  77. left to do. If you want to halt a lookup before completion, just press
  78. the STOP sign in the upper-right corner. (You'll notice that the sign
  79. is normally dimmed; it brightens and becomes active only during the
  80. processing of one of the list boxes.)
  81.  
  82.     When you've filled one or more of the lists, you can highlight and
  83. copy the selected item(s) to the Clipboard so they can be written to a
  84. text file or incorporated into another document. The list boxes in
  85. FONEWORD work just like the file lists in File Manager:  To select a
  86. range of items, click on the first, then hold Shift down as you click
  87. on the last; to select or deselect an individual item without affecting
  88. other items, press Ctrl as you click on it. When you've highlighted all
  89. of your choices, press the Clipboard button at the top of the list to
  90. copy them to the Clipboard.
  91.  
  92.     That's all you need to know to use FONEWORD!  Should you need help
  93. while using the program, just select an item from the help menu. For help
  94. with using a particular on-screen element, tab to that element and press
  95. the F1 key.
  96.  
  97. PROGRAMMING FONEWORD
  98.  
  99.      Visual Basic makes database programming amazingly easy. It takes
  100. just two lines of VB 3.0 code to open a database; another two lines
  101. check whether a given field value exists. I chose to store FONEWORD's
  102. internal database in Paradox format because my informal experimentation
  103. showed that this produced the smallest database file for the word list.
  104. But I could have used any format that Visual Basic supports.
  105.  
  106.     FONEWORD also uses a number of the special controls from VB's
  107. Professional Edition. Specifically, the phone number text box is a Masked
  108. Edit control; the three completion gauges are Gauge controls; and the
  109. four buttons with pictures are graphical Push buttons.
  110.  
  111.     Generating a list of all possible letter combinations is a simple
  112. exercise in recursion--a topic that I'll discuss a little later.
  113. Finding which combinations contain real words is the challenge. A phone
  114. number can contain any word of up to seven letters that has no Q or Z in
  115. it. Fortunately, years ago I compiled an exhaustive word list for my
  116. NAMEGRAM anagram generator. FONEWORD's internal dictionary is a subset
  117. of that list.
  118.  
  119.     In my first crack at programming FONEWORD, I simply imported the word
  120. list directly into the Paradox database FONENUMS.DB so that it contained
  121. a single 7-letter text field that also served as the primary index.
  122. I took each of the up-to-2,187 combinations of letters and checked
  123. whether each of its substrings was a word. A 7-letter text string has
  124. one 7-letter substring, two 6-letter substrings, and so on, for a total
  125. of 28 substrings. With 2,187 combinations times 28 substrings each, the
  126. program might have to perform over 60,000 database lookups!  As a result,
  127. its performance was utterly abysmal--too slow for anyone to actually use.
  128.  
  129.     In fact, however, most of those 60,000 database lookups were redundant.
  130. There are actually only 4,098 distinct words. Where does that number come
  131. from?  Multiplying 3 possible letters for the first digit times 3 for the
  132. second digit and so on, we see that the number of possible words formed by
  133. a string of n digits is 3 to the n power. Thus, the one 7-letter substring
  134. forms 3 to the power of 7 possible words; the two 6-letter substrings
  135. each form 3 to the power of 6 possible words, and so on, for a total of
  136. 4,098. My original algorithm had been looking up most of the possible
  137. words many times. For example, in processing the number 265-5328,
  138. it looked up ``AMJJD'' as a substring of nine different strings,
  139. ranging from ``AMJJDAT'' to ``AMJJDCV.'' My second algorithm carefully
  140. avoided looking up any word more than once. It was better--but it was
  141. still impractically slow.
  142.  
  143.     I found that the solution to improving FONEWORD's performance was to
  144. look at the problem from a completely different angle. As a result, the
  145. current database doesn't contain words at all!  In place of each word,
  146. the database stores the string of digits that you would get by typing
  147. the word on your telephone, together with an integer that encodes
  148. instructions for deriving the original word from the digit string.
  149. Using this as the database, it's necessary to look up only the 28
  150. substrings of the original phone number. That's quite an improvement
  151. --going from over 60,000 database lookups to under 100.
  152.  
  153. FONEWORD'S SECRET CODE
  154.  
  155.      Although they are stored as decimal integers, the integer codes stored
  156. in FONEWORD's database are actually numbers in base 3. A single digit in
  157. base 3 can have the value 0, 1, or 2. If it's 0, the corresponding digit
  158. in the phone number string is replaced by the first possible letter for
  159. that digit. If it's 1, the second possible letter is used; if it's 2,
  160. the third. To decode a digit string, therefore, FONEWORD repeatedly 
  161. divides the decimal code number by 3 and uses the remainder to determine
  162. which letter to use.
  163.  
  164.     The table in Figure 1 (see below) shows the actual process of decoding
  165. the string ``2222537,'' using the code 1900 (2121101 in base 3). The first
  166. remainder is 1, so we replace the first character with the second of the
  167. three possible letters. The second remainder is 0, so we replace the
  168. second character with the first of the possible letters. This continues
  169. until the string is completely decoded. Figure 2 (See below) shows the
  170. Visual Basic function Decode$, which implements the process described
  171. here.
  172.  
  173.     There's one hitch in this scheme:  A given string of digits may well
  174. decode to more than one word. Indeed, from the user's point of view this
  175. is highly desirable. For example, the string ``22737'' has 12 possible
  176. interpretations, including ACRES, BASES, and CAPER. In this case,
  177. therefore, the database should have 12 entries in which the key is
  178. 22737, each with a different code. Like many database systems, however,
  179. Paradox does not permit duplicates in the primary key. Eliminating the
  180. key is not an option because doing so would render database lookups
  181. impossibly slow.
  182.  
  183.     FONEWORD solves this dilemma by appending the letters A, B, C, and
  184. so on to successive key entries for the same digit string. Thus the
  185. second entry for ``22737'' is ``22737A,'' the third ``22737B,'' and so
  186. on. Other solutions may be more elegant, but this technique is economical
  187. in terms of database size.
  188.  
  189.     The function NextMatch$, shown in Figure 3 (See below), can be called
  190. repeatedly to return each entry that matches a given digit string. Its
  191. second parameter is a one-character string, C, which the calling function
  192. must set initially to @. (The ASCII code for the @ character comes just
  193. before A.)  Each call to NextMatch advances C to the next character.
  194. NextMatch returns the decoded word, or an empty string if there was no
  195. match. It also includes logic to handle one-character digit strings
  196. without accessing the database.
  197.  
  198.     Figure 4 (See below) lists the subroutine FindRealWords, which uses
  199. NextMatch to find real words within the input phone number. FindRealWords
  200. simply looks up each of the 28 possible substrings and reports any word
  201. matches by replacing the substring with the corresponding word, set off
  202. by spaces. With the support functions NextMatch$ and Decode$ in place,
  203. FindRealWords is remarkably simple!
  204.  
  205. RECURSION IN FONEWORD
  206.  
  207.      Sooner or later every programmer must grapple with the concept of
  208. recursion. A recursive procedure or function is one that calls itself.
  209. The factorial function is often used as an example of recursion.
  210. The factorial of a positive number n is defined as the product of all
  211. numbers from n down to 1. A recursive definition of this function might
  212. thus be  ``The factorial of 1 or 0 is 1. For any other positive value n,
  213. the factorial is n times the factorial of n-1.''  Note that the definition
  214. includes a provision for the recursion process to end; in this case, the
  215. process finishes when n gets down to 1. Every recursive function must
  216. provide such an outlet.
  217.  
  218.     Unlike some early versions of BASIC, VB 3.0 supports recursion, and
  219. FONEWORD depends on that  to fill the ``All words'' and ``Only words''
  220. list boxes. The function AllCombos, listed in Figure 5 (See below), takes
  221. a string of digits and generates all possible combinations of letters,
  222. inserting the results in the list box named ListAll. Its first parameter,
  223. S, is the string being worked on, and its N parameter is the current
  224. character position. If N is beyond the end of the string, the AllCombos
  225. function adds the completed string to the list box. Otherwise, for each
  226. of the three possible letters corresponding to the Nth digit, AllCombos
  227. replaces the digit with that letter and passes the modified string back
  228. to itself, adding 1 to the value of N in order to process the next digit.
  229.  
  230.     It may be instructive to trace the operation of AllCombos on the
  231. partial phone number ``28.'' Initially, S is 28 and N is 1. AllCombos
  232. replaces the first digit (2) with the letter A and calls itself again.
  233. This second instance of AllCombos receives the parameters A8 and 2, and
  234. in its turn, it replaces the second digit (8) with the letter T and
  235. calls itself again. This time the parameters are AT and 3. Since 3 is
  236. greater than the string's length, AllCombos adds ``AT'' to the list box
  237. and returns.
  238.  
  239.     The second instance of AllCombos now calls itself twice more, passing
  240. ``AU'' and then ``AV'' with the character position 3. After that it returns
  241. to the first instance, which has remained in memory. The first instance
  242. now calls itself, passing ``B8'' and the position 2. By the time this
  243. series of calls finishes, all nine possible combinations are in the list
  244. box.
  245.  
  246.     The function OnlyRealWords, shown in Figure 6 (See Below), uses a
  247. somewhat different type of recursion to find all ``vanity numbers,''
  248. that is, solutions that use all the digits of the phone number.
  249. The function takes two parameters, the input string S and an initially
  250. empty accumulator string SAcc.  OnlyRealWords defines a vanity number as
  251. one that can either be represented by a single real word or one that can 
  252. be divided into two vanity numbers. Using this recursive definition handles
  253. breaking down the original string into any number of substrings. It would,
  254. for example, translate the number 242-4242 into ``A I A I A I A.''
  255.  
  256.     OnlyRealWords starts by seeing whether string S begins with a real
  257. word of any length from 1 character up to the entire string. For each
  258. real word found, it calls itself, passing the remainder of the input
  259. string as the first parameter and appending the found word to the
  260. accumulator string in the second parameter. If it manages to convert
  261. all the digits of the input string, it combines the accumulator with
  262. the most recently found word and adds the result to the list box.
  263. By using recursion, this function avoids spelling out every possible
  264. partition of the input string into one- and six-letter substrings,
  265. two- and five-letter substrings, and so on.
  266.  
  267.     FONEWORD relies on Visual Basic's built-in Clipboard object to move
  268. text from a list box to the Clipboard. Each list box has an associated
  269. push button with a picture of the Clipboard on it. Pressing one of these
  270. buttons calls the procedure ToClip, shown in Figure 8, passing the
  271. associated list box as a parameter. From the list box, ToClip builds a
  272. text string that contains each selected item, separated by carriage return
  273. and line-feed. It takes only one line of code to clear the contents of the
  274. Clipboard and just one more line to copy the built-up text string into the
  275. Clipboard!
  276.  
  277. DEALING WITH LENGTHY ROUTINES
  278.  
  279.    Because Windows is not a preemptive multitasking system, any program
  280. can temporarily slow Windows to a dead stop simply by performing a lengthy
  281. task without giving Windows a chance to process messages. Database lookups
  282. are often such lengthy tasks, during which Windows won't respond to messages.
  283. In some languages, the programmer must write a construct called a PeekMessage
  284. loop, which calls several Windows API functions, just to avoid bringing
  285. Windows to its knees. In Visual Basic, however, the problem is handled by
  286. the built-in DoEvents command. The routines AllCombos, FindRealWords, and
  287. OnlyRealWords all include one or more calls to DoEvents. DoEvents calls
  288. come between other statements, and each database lookup is accomplished
  289. by a single statement, so you'll notice that Windows won't respond to
  290. messages during a database lookup.
  291.  
  292.     If a process takes more than a few seconds, a courteous program will
  293. let the user know how the task is progressing. Each of FONEWORD's list
  294. boxes is associated with a Gauge control--a control that fills up with
  295. color to show how much of the task is complete. Of course, it's up to
  296. the programmer to define what ``complete'' means, by setting the gauge's
  297. Max field to a value that indicates the task has been completed.
  298.  
  299.     AllCombos can calculate in advance how many items will be added:
  300. It simply raises the gauge by one unit for each item added.
  301. FindRealWords calculates the number of substrings it must process and
  302. advances the gauge each time it finishes one substring. Since the amount
  303. of time spent on a given substring will vary, this gauge doesn't advance
  304. smoothly. There's no way for OnlyRealWords to evaluate the number of
  305. recursive calls it will make, so it moves the gauge once for each substring
  306. length from 1 to the original string's length.
  307.  
  308.     The user can now see whether a process is half-done, nearly done, or
  309. barely started. If time is short, the user may want to stop the lengthy
  310. routine before it finishes. In FONEWORD, pressing the STOP button at the
  311. upper right stops the current routines. Pressing this button sets a global
  312. variable called Continue to FALSE, and each of the three routines
  313. terminates when Continue becomes FALSE. The STOP button is dimmed when
  314. a lengthy process is not occurring.
  315.  
  316.     The short Before and After Subroutines listed in Figure 8 are called
  317. to set up each of the three lengthy processes and to clean up afterward.
  318. The Before routine clears the appropriate list box and its item-count line.
  319. It sets Continue to true, changes the mouse pointer to an hourglass, and
  320. sets the STOP button's picture fields to a bright red-and-white stop
  321. -sign image. The After routine dims the STOP button, restores the default
  322. mouse pointer, and reports the item count. The call to MessageBeep,
  323. a Windows API function declared in FONEWORD's declarations section,
  324. either beeps the speaker or causes Windows to play the default .WAV
  325. sound file. Note that this beep will sound even if FONEWORD is minimized.
  326.  
  327. HELP IN FONEWORD
  328.  
  329.    Visual Basic controls have a property called HelpContext ID. If you
  330. associate a help file with your program in the Options|Project dialog,
  331. pressing F1 will bring up the help screen associated with the
  332. HelpContextID of whatever control has the focus. This makes adding
  333. context-sensitive help to a VB application a snap. I used the Windows
  334. Help Magician from Software Interphase to create FONEWORD's help file.
  335. The package's visual orientation makes it much easier to use than the
  336. traditional combination of Word for Windows and the Windows Help
  337. Compiler.
  338.  
  339.     The standard, Microsoft-defined Help menu includes items that show
  340. the help file's contents page, bring up the Search dialog box, display
  341. help on using Help, and present an About dialog box. Visual Basic does
  342. not directly support the first three of these options, so FONEWORD uses
  343. the Windows API function WinHelp, which is defined in its declarations
  344. section. As Figure 9 shows (See below), WinHelp handles all three of
  345. the necessary tasks. Of course, the About FONEWORD dialog box is simply
  346. a second form in the same program.
  347.  
  348. PAYING THE PIPER
  349.  
  350.    In almost any other language, FONEWORD would have been a much bigger
  351. program. Code to handle its user interface and database would have to be
  352. designed, developed, and debugged. By contrast, database access in Visual
  353. Basic is completely handled by support DLLs, and the programmer needs to
  354. write only the highest-level code to create the user interface out of
  355. standard elements.
  356.  
  357.     This simplicity comes at a price, however. The database support files
  358. for Visual Basic programs require just short of a megabyte of disk space.
  359. You'll incur that cost the first time you install any VB program that uses
  360. database functions. Any subsequent VB database programs won't add to that
  361. load, though. And since the VB programs are quite small, if you run a lot
  362. of them, this system of shared resources will ultimately mean a savings
  363. in hard disk space. And if FONEWORD is your first such VB application,
  364. I'm sure it won't be your last!
  365. ---------------------------------------------------------------------------
  366. NEIL J. RUBENKING IS TECHNICAL EDITOR OF PC MAGAZINE.
  367. ---------------------------------------------------------------------------
  368.  
  369.                       Decoding Digits
  370.  
  371. String            Code             Quotient          Remainder
  372.  
  373. 2222537           1900                633                 1
  374.  
  375. B222537           633                 211                 0
  376.  
  377. BA22537           211                 70                  1
  378.  
  379. BAB2537           70                  23                  1
  380.  
  381. BABB537           23                  7                   2
  382.  
  383. BABBL37           7                   2                   1
  384.  
  385. BABBLE7           2                   0                   2
  386.  
  387. BABBLES           0
  388.  
  389. Figure 1:  An entry in FONEWORD's database includes a string of digits
  390. and a code that is used to convert the string into a word.
  391. ------------------------------------------------------------------------
  392.                          DECODE.BAS
  393.  
  394.                        Complete Listing
  395.  
  396.  
  397. Function Decode$ (ByVal S$, ByVal Code%)
  398.   ' This function receives a string of digits from 2 to 9
  399.   ' and an integer that tells how to decode those digits
  400.   ' into a real word. It repeatedly divides the code by
  401.   ' 3 and uses the remainder as an index into the A array,
  402.   ' selecting the first, second, or third letter associated
  403.   ' with the current digit.
  404.   Dim N%, TempS$
  405.   If (Len(S) = 1) And InStr("01", S) Then
  406.     Decode = S
  407.   Else
  408.     TempS = NullStr
  409.     For N = 1 To Len(S)
  410.       TempS = TempS + A(Asc(Mid$(S, N, 1)), Code Mod 3)
  411.       Code = Code \ 3
  412.     Next N
  413.     Decode = TempS
  414.   End If
  415. End Function
  416.  
  417. Figure 2:  The Decode$ function takes a digit string and converts it
  418. into a word by repeatedly dividing a code by 3 to get the base 3 number
  419. it represents.
  420. -----------------------------------------------------------------------
  421.                            NEXTMATC.BAS
  422.  
  423.                           Complete Listing
  424.  
  425.  
  426. Function NextMatch$ (ByVal S$, C$)
  427.   ' Called by FindRealWords and OnlyRealWords
  428.   '
  429.   ' Handles the fact that multiple decodings of the same
  430.   ' string of digits exist. The first is keyed with the
  431.   ' digit string itself, and the later ones have A, B,
  432.   ' C, and so on appended in turn.
  433.   Dim Criteria$, Code%
  434.   NextMatch = NullStr
  435.   If C = "?" Then Exit Function
  436.   If Len(S) = 1 Then
  437.     ' deal with single-digit "words" w/o hitting database
  438.     Select Case S
  439.       Case "0", "1"
  440.         NextMatch = S
  441.       Case "2"
  442.         NextMatch = "A"
  443.       Case "4"
  444.         NextMatch = "I"
  445.       Case ""
  446.         NextMatch = "O"
  447.     End Select
  448.     C = "?"
  449.   Else
  450.     If C = "@" Then
  451.       Criteria = "Foneword = '" + S + "'"
  452.     Else
  453.       Criteria = "Foneword = '" + S + C + "'"
  454.     End If
  455.     MySet.FindFirst Criteria
  456.     If Not MySet.NoMatch Then
  457.       Code = MySet("Code")
  458.       NextMatch = Decode(S, Code)
  459.     End If
  460.     C = Chr$(Asc(C) + 1)
  461.   End If
  462. End Function
  463.  
  464. Figure 3:  The NextMatch$ function checks the database for entries
  465. matching the input string, returning either the next matching word
  466. or a null string.
  467. ------------------------------------------------------------------------
  468.                          FINDREAL.BAS
  469.                         Complete Listing
  470.  
  471.  
  472.  
  473. Sub FindRealWords ()
  474.   ' Called when you press the CommandReal button.
  475.   '
  476.   ' Considers every substring of the phone number that's
  477.   ' at least MinWord in length. If it's in the database,
  478.   ' decodes it into a word and adds the result to the list.
  479.   ' Then it checks for other words made from the same
  480.   ' digits. The key values for these other words will
  481.   ' be the same as the original number with A, B, C
  482.   ' and so on appended in turn.
  483.   Dim Start%, Num%, vLen%, Code%
  484.   Dim S$, SPart$, SDecode$
  485.   Dim Char As String * 1
  486.   vLen = Len(PhoneEdit.ClipText)
  487.   GaugeReal.Max = 1
  488.   For Num = MinWord To vLen
  489.     For Start = 1 To (vLen + 1 - Num)
  490.       GaugeReal.Max = GaugeReal.Max + 1
  491.     Next Start
  492.   Next Num
  493.   GaugeReal.Value = 0
  494.   For Num = MinWord To vLen
  495.     For Start = 1 To (vLen + 1 - Num)
  496.       GaugeReal.Value = GaugeReal.Value + 1
  497.       DoEvents
  498.       If Not Continue Then Exit Sub
  499.       SPart = Mid$(PhoneEdit.ClipText, Start, Num)
  500.       Char = "@"
  501.       SDecode = NextMatch(SPart, Char)
  502.       Do While Len(SDecode) <> 0
  503.         DoEvents
  504.         If Not Continue Then Exit Sub
  505.         S = NullStr
  506.         If Start > 1 Then S = Mid$(PhoneEdit.ClipText, 1, Start - 1) + " "
  507.         S = S + SDecode
  508.         If Start + Num <= vLen Then S = S + " " + Mid$(PhoneEdit.ClipText,
  509.  Start + Num)
  510.         ListReal.AddItem S
  511.         SDecode = NextMatch(SPart, Char)
  512.       Loop
  513.     Next Start
  514.   Next Num
  515.   GaugeReal.Value = GaugeReal.Value + 1
  516. End Sub
  517.  
  518. Figure 4:  FindRealWords repeatedly calls NextMatch$ (Figure 3 (See above))
  519. to identify real words and then lists all real words found within the input
  520. phone number.
  521. ---------------------------------------------------------------------------
  522.                     ALLCOMBO.BAS
  523.                   Complete Listing
  524.  
  525.  
  526. Sub AllCombos (ByVal S$, ByVal N%)
  527.   ' Called when button CommandAll is clicked
  528.   '
  529.   ' Recursive function. Replaces the Nth digit of S with
  530.   ' each of the three possible letters, then calls itself
  531.   ' to handle the N+1th digit for each. When it passes
  532.   ' the LAST digit, it records the completed combination
  533.   ' by adding it to a list box.
  534.   '
  535.   Dim Ch%
  536.   DoEvents
  537.   If Not Continue Then Exit Sub
  538.   If N > Len(S) Then
  539.     ListAll.AddItem S
  540.     GaugeAll.Value = ListAll.ListCount
  541.   Else
  542.     Ch = Asc(Mid$(S, N, 1))
  543.     If (Ch >= 50) And (Ch <= 57) Then
  544.       Mid$(S, N, 1) = A(Ch, 0)
  545.       AllCombos S, N + 1
  546.       Mid$(S, N, 1) = A(Ch, 1)
  547.       AllCombos S, N + 1
  548.       Mid$(S, N, 1) = A(Ch, 2)
  549.       AllCombos S, N + 1
  550.     Else
  551.       AllCombos S, N + 1
  552.     End If
  553.   End If
  554. End Sub
  555.  
  556. Figure 5:  The recursive function AllCombos calls itself repeatedly
  557. to generate all possible combinations of letters found in a given
  558. phone number.
  559. --------------------------------------------------------------------
  560.                              ONLYREAL.BAS
  561.  
  562.                            Complete Listing
  563.  
  564.  
  565.  
  566. Sub OnlyRealWords (ByVal S$, ByVal SAcc$)
  567.   ' Called when you press the CommandOnly button
  568.   '
  569.   ' Checks each prefix of the passed string to see if it's
  570.   ' a word. If so, adds the decoded word to the accumulator
  571.   ' string SAcc and calls itself recursively to handle the
  572.   ' remainder of the string. Only if the string is entirely
  573.   ' converted to words does it add the result to the list.
  574.   Dim N%, SPart$, SDecode$
  575.   Dim Char As String * 1
  576.   If Not Continue Then Exit Sub
  577.   For N = 1 To Len(S)
  578.     ' Only advance the gauge for the first instance
  579.     If Len(SAcc) = 0 Then GaugeOnly.Value = GaugeOnly.Value + 1
  580.     DoEvents
  581.     If Not Continue Then Exit Sub
  582.     SPart = Mid$(S, 1, N)
  583.     Char = "@"
  584.     SDecode = NextMatch(SPart, Char)
  585.     Do While Len(SDecode) <> 0
  586.       DoEvents
  587.       If Not Continue Then Exit Sub
  588.       If N = Len(S) Then
  589.         ListOnly.AddItem Mid$(SAcc + " " + SDecode, 2)
  590.       Else
  591.         OnlyRealWords Mid$(S, N + 1), SAcc + " " + Left$(SDecode, N)
  592.       End If
  593.       SDecode = NextMatch(SPart, Char)
  594.     Loop
  595.   Next N
  596.   ' Only advance the gauge for the first instance
  597.   If Len(SAcc) = 0 Then GaugeOnly.Value = GaugeOnly.Value + 1
  598. End Sub
  599.  
  600. Figure 6:  The OnlyRealWords subroutine locates combinations of words
  601. that completely replace the digits of the original phone number.
  602. ---------------------------------------------------------------------
  603.                         TOCLIP.BAS
  604.  
  605.                       Complete Listing
  606.  
  607.  
  608. Sub ToClip (L As ListBox)
  609.   ' Called when you press one of the clipboard buttons
  610.   '
  611.   ' Copies the selected items from the associated list
  612.   ' box to the clipboard.
  613.   Dim N%, Text$
  614.   Text = NullStr
  615.   If L.ListCount = 0 Then Exit Sub
  616.   For N = 0 To L.ListCount - 1
  617.     If L.Selected(N) Then
  618.       Text = Text + L.List(N)
  619.       Text = Text + Chr$(13) + Chr$(10)
  620.     End If
  621.   Next N
  622.   If Len(Text) = 0 Then
  623.     MsgBox "No items are selected", 0
  624.   Else
  625.     Clipboard.Clear
  626.     Clipboard.SetText Text
  627.   End If
  628. End Sub
  629.  
  630. Figure 7:  Visual Basic's Clipboard object makes it easy for this
  631. routine to copy selected items from a list box to the Windows Clipboard.
  632. -----------------------------------------------------------------------
  633.                          BEFORAFT.BAS
  634.  
  635.                        Complete Listing
  636.  
  637.  
  638. Sub Before (Lis As ListBox, Lab As Label)
  639.   Continue = True
  640.   Lis.Clear
  641.   Lab.Caption = NullStr
  642.   Form1.MousePointer = 11
  643.   PushStop.PictureUp = ImageStopUp.Picture
  644.   PushStop.PictureDown = ImageStopDn.Picture
  645. End Sub
  646. Sub After (Lis As ListBox, Lab As Label)
  647.   PushStop.PictureUp = ImageDiStopUp.Picture
  648.   PushStop.PictureDown = ImageDiStopDn.Picture
  649.   Form1.MousePointer = 0
  650.   Lab.Caption = Lis.ListCount + " Items"
  651.   MessageBeep (0)
  652. End Sub
  653.  
  654. Figure 8:  Since FONEWORD's search routines can take several minutes,
  655. the routines Before and After set up for lengthy processing and clean
  656. up afterward.
  657. -----------------------------------------------------------------------
  658.                         HELPMENU.BAS
  659.                       Complete Listing
  660.  
  661.  
  662. Sub HelpMenu_Click (Index As Integer)
  663.   ' Note that WinHelp and WinHelpByNum are declared in
  664.   ' the declarations section, to give this VB program
  665.   ' access to the Windows API function WinHelp.
  666.   Dim Success%
  667.   Select Case Index
  668.     Case 101
  669.       Success = WinHelpByNum(Form1.hWnd, App.HelpFile, HELP_CONTENTS, 0)
  670.     Case 102
  671.       Success = WinHelp(Form1.hWnd, App.HelpFile, HELP_PARTIALKEY, "")
  672.     Case 103
  673.       Success = WinHelpByNum(Form1.hWnd, App.HelpFile, HELP_HELPONHELP, 0)
  674.     Case 105
  675.       Form2.Show
  676.   End Select
  677. End Sub
  678.  
  679. Figure 9:  FONEWORD's Help menu choices rely on the Windows API function
  680. WinHelp to process the standard Windows Help menu choices.
  681. ------------------------------------------------------------------------
  682.