home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / SOUNDEX4.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  5KB  |  169 lines

  1. /* +++Date last modified: 05-Jul-1997 */
  2.  
  3. /*
  4. **  Variant Soundex Algorithm (Algorithm #4), Optimized for use with Surnames
  5. **
  6. **  Written by Joe Celko. Originally published in "The C Gazette" vol. 4 nr. 2
  7. **  Source code may be freely used is source is acknowledged
  8. **  Object code may be freely used
  9. **
  10. **  Uses STRUPR.C, also from SNIPPETS
  11. */
  12.  
  13. /*
  14. **  Preserves first character, uppercase name, drop non-alpha characters,
  15. **  convert letters to Soundex digits, and returns first N letters.
  16. **  Many of the steps here could be combined into the same loop, but
  17. **  they are kept separate for clarity and to give the user a chance
  18. **  to experiment with changes.
  19. */
  20.  
  21. #include <string.h>
  22. #include "phonetic.h"
  23. #include "snip_str.h"
  24.  
  25. #define WBUFSIZE 512
  26.  
  27. void soundex4(const char *instr, char *outstr, int N)
  28. {
  29.       char *p, *p1;
  30.       int i;
  31.       char workbuf[WBUFSIZE + 1];
  32.       char priorletter;
  33.  
  34.       /* Make a working copy  */
  35.  
  36.       strncpy(workbuf, instr, WBUFSIZE);
  37.       workbuf[WBUFSIZE] = NUL;
  38.       strupr(workbuf);
  39.  
  40.       /* Convert all vowels to 'A'  */
  41.  
  42.       for (p = workbuf; *p; ++p)
  43.       {
  44.             if (strchr("AEIOUY", *p))
  45.                   *p = 'A';
  46.       }
  47.  
  48.       /* Prefix transformations: done only once on the front of a name  */
  49.  
  50.       if (Success_ == strncmp(workbuf, "MAC", 3))     /* MAC to MCC     */
  51.             workbuf[1] = 'C';
  52.       else if (Success_ == strncmp(workbuf, "KN", 2)) /* KN to NN       */
  53.             workbuf[0] = 'N';
  54.       else if ('K' == workbuf[0])                     /* K to C         */
  55.             workbuf[0] = 'C';
  56.       else if (Success_ == strncmp(workbuf, "PF", 2)) /* PF to FF       */
  57.             workbuf[0] = 'F';
  58.       else if (Success_ == strncmp(workbuf, "SCH", 3))/* SCH to SSS     */
  59.             workbuf[1] = workbuf[2] = 'S';
  60.  
  61.       /*
  62.       ** Infix transformations: done after the first letter,
  63.       ** left to right
  64.       */
  65.  
  66.       while ((p = strstr(workbuf, "DG")) > workbuf)   /* DG to GG       */
  67.             p[0] = 'G';
  68.       while ((p = strstr(workbuf, "CAAN")) > workbuf) /* CAAN to TAAN   */
  69.             p[0] = 'T';
  70.       while ((p = strchr(workbuf, 'D')) > workbuf)    /* D to T         */
  71.             p[0] = 'T';
  72.       while ((p = strstr(workbuf, "NST")) > workbuf)  /* NST to NSS     */
  73.             p[2] = 'S';
  74.       while ((p = strstr(workbuf, "AV")) > workbuf)   /* AV to AF       */
  75.             p[1] = 'F';
  76.       while ((p = strchr(workbuf, 'Q')) > workbuf)    /* Q to G         */
  77.             p[0] = 'G';
  78.       while ((p = strchr(workbuf, 'Z')) > workbuf)    /* Z to S         */
  79.             p[0] = 'S';
  80.       while ((p = strchr(workbuf, 'M')) > workbuf)    /* M to N         */
  81.             p[0] = 'N';
  82.       while ((p = strstr(workbuf, "KN")) > workbuf)   /* KN to NN       */
  83.             p[0] = 'N';
  84.       while ((p = strchr(workbuf, 'K')) > workbuf)    /* K to C         */
  85.             p[0] = 'C';
  86.       while ((p = strstr(workbuf, "AH")) > workbuf)   /* AH to AA       */
  87.             p[1] = 'A';
  88.       while ((p = strstr(workbuf, "HA")) > workbuf)   /* HA to AA       */
  89.             p[0] = 'A';
  90.       while ((p = strstr(workbuf, "AW")) > workbuf)   /* AW to AA       */
  91.             p[1] = 'A';
  92.       while ((p = strstr(workbuf, "PH")) > workbuf)   /* PH to FF       */
  93.             p[0] = p[1] = 'F';
  94.       while ((p = strstr(workbuf, "SCH")) > workbuf)  /* SCH to SSS     */
  95.             p[0] = p[1] = 'S';
  96.  
  97.       /*
  98.       ** Suffix transformations: done on the end of the word,
  99.       ** right to left
  100.       */
  101.  
  102.       /* (1) remove terminal 'A's and 'S's      */
  103.  
  104.       for (i = strlen(workbuf) - 1;
  105.             (i > 0) && ('A' == workbuf[i] || 'S' == workbuf[i]);
  106.             --i)
  107.       {
  108.             workbuf[i] = NUL;
  109.       }
  110.  
  111.       /* (2) terminal NT to TT      */
  112.  
  113.       for (i = strlen(workbuf) - 1;
  114.             (i > 1) && ('N' == workbuf[i - 1] || 'T' == workbuf[i]);
  115.             --i)
  116.       {
  117.             workbuf[i - 1] = 'T';
  118.       }
  119.  
  120.       /* Now strip out all the vowels except the first     */
  121.  
  122.       p = p1 = workbuf;
  123.       while (NUL != (*p1++ = *p++))
  124.       {
  125.             while ('A' == *p)
  126.                   ++p;
  127.       }
  128.  
  129.       /* Remove all duplicate letters     */
  130.  
  131.       p = p1 = workbuf;
  132.       priorletter = NUL;
  133.       do {
  134.             while (*p == priorletter)
  135.                   ++p;
  136.             priorletter = *p;
  137.       } while (NUL != (*p1++ = *p++));
  138.  
  139.       /* Finish up      */
  140.  
  141.       strncpy(outstr, workbuf, N);
  142.       outstr[N] = NUL;
  143. }
  144.  
  145. #ifdef TEST
  146.  
  147. #include <stdio.h>
  148. #include <stdlib.h>
  149.  
  150. main(int argc, char *argv[])
  151. {
  152.       char outbuf[80];
  153.       int N;
  154.  
  155.       if (argc != 3)
  156.       {
  157.             puts("Usage: SOUNDEX4 string length");
  158.             return EXIT_FAILURE;
  159.       }
  160.  
  161.       soundex4(argv[1], outbuf, N = atoi(argv[2]));
  162.  
  163.       printf("soundex4(\"%s\", %d) => \"%s\"\n", argv[1], N, outbuf);
  164.  
  165.       return EXIT_SUCCESS;
  166. }
  167.  
  168. #endif /* TEST */
  169.