home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Database / CLIPR503.W96 / SOUNDEX._ / SOUNDEX.
Text File  |  1995-06-20  |  4KB  |  210 lines

  1. /***
  2. *
  3. *  Soundex.c
  4. *
  5. *  Clipper SOUNDEX() function
  6. *
  7. *  Copyright (c) 1990-1993, Computer Associates International, Inc.
  8. *  All rights reserved.
  9. *
  10. */
  11.  
  12. #include "extend.api"
  13.  
  14.  
  15. /* used below */
  16. #define ISALPHA(c)  ( (c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z' )
  17. #define TOUPPER(c)  ( (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c) )
  18.  
  19. #define SOUNDEX_LENGTH    4
  20.  
  21.  
  22. /***
  23. *   step2()
  24. *   Return soundex result for a single letter.
  25. */
  26.  
  27. static char step2(char c)
  28.  
  29. {
  30.     switch (c)
  31.     {
  32.         case 'B':
  33.         case 'F':
  34.         case 'P':
  35.         case 'V':
  36.             return ('1');
  37.  
  38.         case 'C':
  39.         case 'G':
  40.         case 'J':
  41.         case 'K':
  42.         case 'Q':
  43.         case 'S':
  44.         case 'X':
  45.         case 'Z':
  46.             return ('2');
  47.  
  48.         case 'D':
  49.         case 'T':
  50.             return ('3');
  51.  
  52.         case 'L':
  53.             return ('4');
  54.  
  55.  
  56.         case 'M':
  57.         case 'N':
  58.             return ('5');
  59.  
  60.         case 'R':
  61.             return ('6');
  62.  
  63.         case 'A':
  64.         case 'E':
  65.         case 'H':
  66.         case 'I':
  67.         case 'O':
  68.         case 'U':
  69.         case 'W':
  70.         case 'Y':
  71.             return (NIL);
  72.     }
  73.  
  74.     /* bad param -- return something obviously wrong */
  75.     return ('9');
  76. }
  77.  
  78.  
  79. /***
  80. *   SoundexC()
  81. *   Convert a string to a soundex code (C-callable).
  82. *
  83. *    "Soundex" algorithm is standard Odell/Russell (1918):
  84. *
  85. *    Produce a code of the form "letter, digit, digit, digit"
  86. *    using these rules:
  87. *
  88. *    1)    Retain the first letter unchanged.
  89. *
  90. *    2)    For each succeeding letter, produce a result based
  91. *        on the following table:
  92. *
  93. *        letter                            result
  94. *
  95. *        B, F, P, V                        digit 1
  96. *        C, G, J, K, Q, S, X, Z            digit 2
  97. *        D, T                            digit 3
  98. *        L                                digit 4
  99. *        M, N                            digit 5
  100. *        R                                digit 6
  101. *        A, E, H, I, O, U, W, Y            (nothing)
  102. *
  103. *
  104. *    3)    If two or more adjacent letters produce the same
  105. *        result in step 2, ignore all but the first of the
  106. *        adjacent letters.
  107. *
  108. *    4)  Repeat steps 2 and 3 until three digits have been
  109. *        produced or until the source is exhausted.
  110. *
  111. *    5)    If less than three digits were produced, right-fill
  112. *        with zeros.
  113. *
  114. *
  115. *    Notes:
  116. *
  117. *    Non-alpha characters are ignored entirely; letters which
  118. *    are separated only by non-alpha characters are considered
  119. *    adjacent.  If the source contains no alpha characters, a
  120. *    value of "0000" is returned.
  121. *
  122. *    Case is not significant.
  123. *
  124. *    Letters which produce (nothing) in step 2 are still
  125. *    significant with respect to step 3.  That is, two letters
  126. *    which produce the same digit are not considered adjacent
  127. *    if they are separated by a letter that produces (nothing).
  128. *    This is in accordance with the original algorithm.
  129. *
  130. *    This C-callable function returns a pointer to a static
  131. *    buffer.  The buffer is overwritten by successive calls.
  132. */
  133.  
  134. static char *SoundexC(char *source, short len)
  135.  
  136. {
  137.     static char code[SOUNDEX_LENGTH+1] = "";
  138.  
  139.     short i;
  140.     short j;
  141.     char c;
  142.     char result;
  143.     char prev;
  144.  
  145.  
  146.     /* make Soundex code */
  147.     for ( i = 0, j = 0, prev = NIL;  i < len && j < SOUNDEX_LENGTH;  i++ )
  148.     {
  149.         c = TOUPPER(source[i]);
  150.  
  151.         if ( ISALPHA(c) )
  152.         {
  153.             result = step2(c);
  154.  
  155.             if (j == 0)
  156.             {
  157.                 /* retain first letter */
  158.                 code[j++] = c;
  159.             }
  160.             else if ( result != NIL && result != prev )
  161.             {
  162.                 /* store soundex code */
  163.                 code[j++] = result;
  164.             }
  165.  
  166.             prev = result;
  167.         }
  168.     }
  169.  
  170.  
  171.     /* right fill with zeros */
  172.     while (j < SOUNDEX_LENGTH)
  173.         code[j++] = '0';
  174.  
  175.  
  176.     return (code);
  177. }
  178.  
  179.  
  180. /***
  181. *   SOUNDEX()
  182. *   Convert a string to a "Soundex" code (Clipper-callable).
  183. *
  184. *   cSoundexCode := SOUNDEX(cString)
  185. */
  186.  
  187. CLIPPER SOUNDEX(void)
  188.  
  189. {
  190.     char *code;
  191.  
  192.  
  193.     if ( PCOUNT >= 1 && ISCHAR(1) )
  194.     {
  195.         code = SoundexC( _parc(1), _parclen(1) );
  196.     }
  197.     else
  198.     {
  199.         code = "0000";
  200.     }
  201.  
  202.  
  203.     _retclen(code, SOUNDEX_LENGTH);
  204. }
  205.  
  206.  
  207.  
  208.  
  209. 
  210.