home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 1.0 / Image.iso / toolbox / ntserver / wtsource / soundex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-07  |  21.1 KB  |  633 lines

  1. /****************************************************************************
  2. *****************************************************************************
  3. FILE      : soundex.c
  4. FUNCTION  : This module contains the two algorithms SOUNDEX and PHONIX as 
  5.             they were defined by Gadd.
  6. NOTES     : This is an ANSI-C version of the original C++ file.
  7. LITERATURE: T.N. Gadd: 'Fishing fore Werds': Phonetic Retrieval of written 
  8.             text in Information Retrieval Systems, Program 22/3, 1988, 
  9.             p.222-237.
  10.             T.N. Gadd: PHONIX --- The Algorithm, Program 24/4, 1990, 
  11.             p.363-366.
  12. *****************************************************************************
  13. ****************************************************************************/
  14.  
  15. /* #define TEST */       /* activates procedures main() and PrintCode() */
  16. /* #define DEBUG */      /* activates some debug information            */
  17.  
  18. #include <ctype.h>
  19. #include <string.h>
  20.  
  21. #ifdef TEST
  22. #include <stdio.h>
  23. #endif /* TEST  */
  24.  
  25. #ifdef WIN32
  26. #include <stdio.h>
  27. #endif /* WIN32  */
  28.  
  29. /****************************************************************************
  30. NAME    : StrDel
  31. INPUT   : char *DelPos --- pointer to first char to be deleted
  32.           int  DelSize --- number of chars to be deleted
  33. OUTPUT  : char *DelPos 
  34. FUNCTION: This procedure deletes DelSize chars at position DelPos and moves
  35.           the remaining chars left to DelPos.
  36. EXAMPLE : If Del is pointing at the L of the string "DELETE" the call
  37.           StrDel(Del, 2) will return Del pointing at "TE". 
  38. ****************************************************************************/
  39. void StrDel (DelPos, DelSize)
  40. char *DelPos;
  41. int  DelSize;
  42. {
  43.   /* move chars left */
  44.   char *Help = DelPos + DelSize;
  45.   while (*Help)
  46.     *DelPos++ = *Help++;
  47.  
  48.   /* move trailing \0 */
  49.   *DelPos = *Help;
  50. }
  51.  
  52.  
  53. /****************************************************************************
  54. NAME    : StrIns
  55. INPUT   : char *InsPos --- pointer to insert position
  56. OUTPUT  : char *InStr  --- new string to be inserted
  57. FUNCTION: StrIns moves the chars at position InsPos right and copies the
  58.           string InsStr into this free space.
  59. EXAMPLE : If Ins is pointing at the S of the string "INSERT" the call
  60.           StrIns(Ins, "NEW") will return Ins pointing at "NEWSERT". 
  61. ****************************************************************************/
  62. void StrIns (InsPos, InsStr)
  63. char *InsPos;
  64. char *InsStr;
  65. {
  66.   int i;
  67.   int MoveSize = strlen(InsStr);
  68.  
  69.   /* move chars right */
  70.   for (i = strlen(InsPos)+1; i >= 0; i--)
  71.     InsPos[i+MoveSize] = InsPos[i];
  72.  
  73.   /* copy InsStr to InsPos */
  74.   while (*InsStr)
  75.     *InsPos++ = *InsStr++;
  76. }
  77.  
  78.  
  79. /****************************************************************************
  80. NAME    : IsVowel
  81. INPUT   : char c --- char to be examined
  82. OUTPUT  : int    --- 1 or 0
  83. FUNCTION: IsVowel checks if c is an uppercase vowel or an uppercase Y. If c
  84.           is one of those chars IsVowel will return a 1, else it will return
  85.           a 0.
  86. ****************************************************************************/
  87. int IsVowel (c)
  88. unsigned char c;
  89. {
  90.   return (c == 'A') || (c == 'E') || (c == 'I') ||
  91.     (c == 'O') || (c == 'U') || (c == 'Y') ||
  92.       (c == 0304) || (c == 0344) || (c == 0334) ||
  93.         (c == 0366) || (c == 0326) || (c == 0374);
  94. }
  95.  
  96.  
  97. /****************************************************************************
  98. NAME    : SoundexCode
  99. INPUT   : char *Name --- string to be calculated
  100. OUTPUT  : char *Key  --- soundex code for Name
  101. FUNCTION: This procedure calculates a four-letter soundex code for the string 
  102.           Name and returns this code in the string Key.
  103. ****************************************************************************/
  104. #define SoundexLen 4      /* length of a soundex code */
  105. #define SoundexKey "Z000" /* default key for soundex code */
  106.  
  107. char SCode(c)
  108. unsigned char c;
  109. {
  110.   /* set letter values */
  111.   static int  Code[] = {0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 
  112.                           1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2};
  113.  
  114.   if (c == 95) return(2); /* german sz */
  115.   return(Code[toupper(c)-'A']);
  116. }
  117.  
  118. void SoundexCode (Name, Key)
  119. char *Name;
  120. char *Key;
  121. {
  122.   char LastLetter;
  123.   int  Index;
  124.  
  125.   /* set default key */
  126.   strcpy(Key, SoundexKey);
  127.  
  128.   /* keep first letter */
  129.   Key[0] = *Name;
  130.   LastLetter = *Name;
  131.   Name++;
  132.  
  133.   /* scan rest of string */
  134.   for (Index = 1; (Index < SoundexLen) && *Name; Name++)
  135.   {
  136.     /* use only letters */
  137.     if (isalpha(*Name))
  138.     {
  139.       /* ignore duplicate successive chars */
  140.       if (LastLetter != *Name)
  141.       {
  142.         /* new LastLetter */
  143.         LastLetter = *Name;
  144.  
  145.         /* ignore letters with code 0 */
  146.         if (SCode(*Name) != 0)
  147.         {
  148.           Key[Index] = '0' + SCode(*Name);
  149.           Index++;
  150.         }
  151.       }
  152.     }
  153.   }
  154. }
  155.  
  156.  
  157. /****************************************************************************
  158. NAME    : PhonixCode
  159. INPUT   : char *Name --- string to be calculated
  160. OUTPUT  : char *Key  --- phonix code for Name
  161. FUNCTION: This procedure calculates a eight-letter phonix code for the string 
  162.           Name and returns this code in the string Key.
  163. ****************************************************************************/
  164. #define PhonixLen 8          /* length of a phonix code */
  165. #define PhonixKey "Z0000000" /* default key for phonix code */
  166.  
  167. void PhonixCode (Name, Key)
  168. char *Name;
  169. char *Key;
  170. {
  171.   int  Code[25];
  172.   char LastLetter;
  173.   int  Index;
  174.  
  175.   /* set letter values */
  176.   Code[0]  = 0;
  177.   Code[1]  = 1;
  178.   Code[2]  = 2;
  179.   Code[3]  = 3;
  180.   Code[4]  = 0;
  181.   Code[5]  = 7;
  182.   Code[6]  = 2;
  183.   Code[7]  = 0;
  184.   Code[8]  = 0;
  185.   Code[9]  = 2;
  186.   Code[10] = 2;
  187.   Code[11] = 4;
  188.   Code[12] = 5;
  189.   Code[13] = 5;
  190.   Code[14] = 0;
  191.   Code[15] = 1;
  192.   Code[16] = 2;
  193.   Code[17] = 6;
  194.   Code[18] = 8;
  195.   Code[19] = 3;
  196.   Code[20] = 0;
  197.   Code[21] = 7;
  198.   Code[22] = 0;
  199.   Code[23] = 8;
  200.   Code[24] = 0;
  201.   Code[25] = 8;
  202.  
  203.   /* set default key */
  204.   strcpy(Key, PhonixKey);
  205.  
  206.   /* keep first letter or replace it with '$' */
  207.   Key[0] = IsVowel(*Name) ? '$' : *Name;
  208.   LastLetter = *Name;
  209.   Name++;
  210.  
  211.   /* NOTE: Gadd replaces vowels being the first letter of the  */
  212.   /* word with a 'v'. Due to the implementation of WAIS all    */
  213.   /* letters will be lowercased. Therefore '$' is used instead */
  214.   /* of 'v'.                                                   */          
  215.  
  216.   /* scan rest of string */
  217.   for (Index = 1; (Index < PhonixLen) && *Name; Name++)
  218.   {
  219.     /* use only letters */
  220.     if (isalpha(*Name))
  221.     {
  222.       /* ignore duplicate successive chars */
  223.       if (LastLetter != *Name)
  224.       {
  225.         LastLetter = *Name;
  226.  
  227.         /* ignore letters with code 0 except as separators */
  228.         if (Code[toupper(*Name)-'A'] != 0)
  229.         {
  230.           Key[Index] = '0' + Code[toupper(*Name)-'A'];
  231.           Index++;
  232.         }
  233.       }
  234.     }
  235.   }
  236. }
  237.  
  238.  
  239. /****************************************************************************
  240. NAME    : PhonixReplace1
  241. INPUT   : int  where    --- replace OldStr only if it occurs at this position
  242.           char *Name    --- string to work
  243.           char *OldStr  --- old letter group to delete
  244.           char *NewStr  --- new letter group to insert
  245.           int  CondPre  --- condition referring to letter before OldStr
  246.           int  CondPost --- condition referring to letter after OldStr
  247. OUTPUT  : char *Name    --- Name with replaced letter group
  248. FUNCTION: This procedure replaces the letter group OldStr with the letter 
  249.           group NewStr in the string Name, regarding the position of OldStr
  250.           where (START, MIDDLE, END, ALL) and the conditions CondPre and 
  251.           CondPost (NON, VOC, CON).
  252. EXAMPLE : PhonixReplace1(START, "WAWA", "W", "V", NON, NON) replaces only the
  253.           first W with a V because of the condition START.
  254. EXAMPLE : PhonixReplace1(START, "WAWA", "W", "V", NON, CON) replaces neither
  255.           the first W with a V (because of the condition CON, i.e. a consonant
  256.           must follow the W) nor the second W (because of the condition START).
  257. ****************************************************************************/
  258. #define NON    1  /* no condition     */
  259. #define VOC    2  /* vowel needed     */ 
  260. #define CON    3  /* consonant needed */
  261.  
  262. #define START  1  /* condition refers to beginning of Name */
  263. #define MIDDLE 2  /* condition refers to middle of Name    */
  264. #define END    3  /* condition refers to EndPos of Name    */
  265. #define ALL    4  /* condition refers to whole Name        */
  266.  
  267. void PhonixReplace1 (Where, Name, OldStr, NewStr, CondPre, CondPost)
  268. int  Where;
  269. char *Name;
  270. char *OldStr;
  271. char *NewStr;
  272. int  CondPre;
  273. int  CondPost;
  274. {
  275.   char *OldStrPos;
  276.   char *EndPos;
  277.   char *NamePtr = Name;
  278.  
  279.   /* vowels before or after OldStr */
  280.   char LetterPre;  /* letter before OldStr */
  281.   char LetterPost; /* letter after OldStr  */
  282. #ifndef WIN32
  283.   int  VowelPre;   /* LetterPre is vowel?  */
  284.   int  VowelPost;  /* LetterPost is vowel? */
  285. #endif
  286.   int  OkayPre;    /* pre-condition okay?  */
  287.   int  OkayPost;   /* post-condition okay? */
  288.  
  289.   do
  290.   { 
  291.     /* find OldStr in NamePtr */
  292.     OldStrPos = strstr(NamePtr, OldStr);
  293.  
  294.     /* find EndPos of Name */
  295.     EndPos = &Name[strlen(Name)-strlen(OldStr)];
  296.  
  297.     /* check conditions if OldStrPos != NULL */
  298.     if (OldStrPos)
  299.     {
  300.       /* vowel before OldStrPos */
  301.       LetterPre = *(OldStrPos-1);
  302.       /* vowel after OldStrPos+strlen(OldStr) */
  303.       LetterPost = *(OldStrPos+strlen(OldStr));
  304.  
  305.       /* check conditions */
  306.       switch (CondPre)
  307.       {
  308.         case NON: OkayPre = 1;
  309.                   break;
  310.         case VOC: OkayPre = LetterPre ? IsVowel(LetterPre) : 0;
  311.                   break;
  312.         case CON: OkayPre = LetterPre ? !IsVowel(LetterPre) : 0;
  313.                   break;
  314.         default : OkayPre = 0;
  315.                   break;
  316.       }
  317.       switch (CondPost)
  318.       {
  319.         case NON: OkayPost = 1;
  320.                   break;
  321.         case VOC: OkayPost = LetterPost ? IsVowel(LetterPost) : 0;
  322.                   break;
  323.         case CON: OkayPost = LetterPost ? !IsVowel(LetterPost) : 0;
  324.                   break;
  325.         default : OkayPost = 0;
  326.                   break;
  327.       }
  328.     }
  329.  
  330.     /* replace OldStr with NewStr */
  331.     if (OldStrPos && OkayPre && OkayPost &&
  332.        ((Where == START)  && (OldStrPos == Name) ||
  333.         (Where == MIDDLE) && (OldStrPos != Name) && (OldStrPos != EndPos) ||
  334.         (Where == END)    && (OldStrPos == EndPos)  ||
  335.         (Where == ALL)))
  336.     {
  337.       /* replace old letter group with new letter group */
  338.       StrDel(OldStrPos, strlen(OldStr));
  339.       StrIns(OldStrPos, NewStr);
  340.  
  341.       /* advance NamePtr to the position of OldStr */
  342.       NamePtr = OldStrPos;
  343.  
  344. #ifdef DEBUG
  345.       printf("Replace = %s-->%s\n", OldStr, NewStr);  
  346. #endif /* DEBUG */
  347.     }
  348.     else
  349.       /* advance NamePtr one char */
  350.       NamePtr++;
  351.   }
  352.   while (OldStrPos);
  353. }
  354.  
  355.  
  356. /****************************************************************************
  357. NAME    : PhonixReplace2
  358. INPUT   : int  where   --- replace OldStr only if it occurs at this position
  359.           char *Name   --- string to work
  360.           char *OldStr --- old letter group to delete
  361.           char *NewStr --- new letter group to insert
  362. OUTPUT  : char *Name   --- Name with replaced letter group
  363. FUNCTION: This procedure replaces the letter group OldStr with the letter 
  364.           group NewStr in the string Name, regarding the position of OldStr
  365.           where (START, MIDDLE, END, ALL).
  366. EXAMPLE : PhonixReplace2(START, "WAWA", "W", "V") replaces only the first W 
  367.           with a V because of the condition START.
  368. ****************************************************************************/
  369. void PhonixReplace2 (Where, Name, OldStr, NewStr)
  370. int  Where;
  371. char *Name;
  372. char *OldStr;
  373. char *NewStr;
  374. {
  375.   char *OldStrPos;
  376.   char *EndPos;
  377.   char *NamePtr = Name;
  378.  
  379.   do
  380.   { 
  381.     /* find OldStr in NamePtr */
  382.     OldStrPos = strstr(NamePtr, OldStr);
  383.  
  384.     /* find EndPos of Name */
  385.     EndPos = &Name[strlen(Name)-strlen(OldStr)];
  386.  
  387.     /* replace OldStr with NewStr */
  388.     if (OldStrPos &&
  389.        ((Where == START)  && (OldStrPos == Name) ||
  390.         (Where == MIDDLE) && (OldStrPos != Name) && (OldStrPos != EndPos) ||
  391.         (Where == END)    && (OldStrPos == EndPos)  ||
  392.         (Where == ALL)))
  393.     { 
  394.       /* replace old letter group with new letter group */
  395.       StrDel(OldStrPos, strlen(OldStr));
  396.       StrIns(OldStrPos, NewStr);
  397.  
  398.       /* advance NamePtr to the position of OldStr */
  399.       NamePtr = OldStrPos;
  400.  
  401. #ifdef DEBUG
  402.       printf("Replace = %s-->%s\n", OldStr, NewStr);  
  403. #endif /* DEBUG */
  404.     }
  405.     else
  406.       /* advance NamePtr one char */
  407.       NamePtr++;
  408.   }
  409.   while (OldStrPos);
  410. }
  411.  
  412.  
  413. /****************************************************************************
  414. NAME    : Phonix
  415. INPUT   : char *Name --- string to calculate phonix code for
  416. OUTPUT  : char *Key  --- phonix code of Name
  417. FUNCTION: Phonix calculates the phonix code for the string Name.
  418. ****************************************************************************/
  419. void Phonix (Name, Key)
  420. char *Name;
  421. char *Key;
  422. {
  423.   /* use new variable NewName to remain Name unchanged */
  424.   char NewName[50];
  425.   int  i;
  426.  
  427.   strcpy(NewName, Name);
  428.  
  429.   /* uppercase NewName */
  430. #ifdef WIN32
  431.   for (i=0; i < (int)strlen(NewName); i++)
  432. #else
  433.   for (i=0; i < strlen(NewName); i++)
  434. #endif
  435.     if (islower(NewName[i])) 
  436.       NewName[i] = toupper(NewName[i]);
  437.  
  438. #ifdef DEBUG
  439.   printf("Name    = %s\n", NewName);  
  440. #endif /* DEBUG */
  441.  
  442.   /* replace letter groups according to Gadd's definition */
  443.   PhonixReplace2(ALL   , NewName, "DG"   , "G"    );
  444.   PhonixReplace2(ALL   , NewName, "CO"   , "KO"   );
  445.   PhonixReplace2(ALL   , NewName, "CA"   , "KA"   );
  446.   PhonixReplace2(ALL   , NewName, "CU"   , "KU"   );
  447.   PhonixReplace2(ALL   , NewName, "CY"   , "SI"   );
  448.   PhonixReplace2(ALL   , NewName, "CI"   , "SI"   );
  449.   PhonixReplace2(ALL   , NewName, "CE"   , "SE"   );
  450.   PhonixReplace1(START , NewName, "CL"   , "KL"   , NON, VOC);
  451.   PhonixReplace2(ALL   , NewName, "CK"   , "K"    );
  452.   PhonixReplace2(END   , NewName, "GC"   , "K"    );
  453.   PhonixReplace2(END   , NewName, "JC"   , "K"    );
  454.   PhonixReplace1(START , NewName, "CHR"  , "KR"   , NON, VOC);
  455.   PhonixReplace1(START , NewName, "CR"   , "KR"   , NON, VOC);
  456.   PhonixReplace2(START , NewName, "WR"   , "R"    );
  457.   PhonixReplace2(ALL   , NewName, "NC"   , "NK"   );
  458.   PhonixReplace2(ALL   , NewName, "CT"   , "KT"   );
  459.   PhonixReplace2(ALL   , NewName, "PH"   , "F"    );
  460.   PhonixReplace2(ALL   , NewName, "AA"   , "AR"   );
  461.   PhonixReplace2(ALL   , NewName, "SCH"  , "SH"   );
  462.   PhonixReplace2(ALL   , NewName, "BTL"  , "TL"   );
  463.   PhonixReplace2(ALL   , NewName, "GHT"  , "T"    );
  464.   PhonixReplace2(ALL   , NewName, "AUGH" , "ARF"  );
  465.   PhonixReplace1(MIDDLE, NewName, "LJ"   , "LD"   , VOC, VOC);
  466.   PhonixReplace2(ALL   , NewName, "LOUGH", "LOW"  );
  467.   PhonixReplace2(START , NewName, "Q"    , "KW"   );
  468.   PhonixReplace2(START , NewName, "KN"   , "N"    );
  469.   PhonixReplace2(END   , NewName, "GN"   , "N"    );
  470.   PhonixReplace2(ALL   , NewName, "GHN"  , "N"    );
  471.   PhonixReplace2(END   , NewName, "GNE"  , "N"    );
  472.   PhonixReplace2(ALL   , NewName, "GHNE" , "NE"   );
  473.   PhonixReplace2(END   , NewName, "GNES" , "NS"   );
  474.   PhonixReplace2(START , NewName, "GN"   , "N"    );
  475.   PhonixReplace1(MIDDLE, NewName, "GN"   , "N"    , NON, CON);
  476.   PhonixReplace1(END   , NewName, "GN"   , "N"    , NON, NON); /* NON,CON */
  477.   PhonixReplace2(START , NewName, "PS"   , "S"    );
  478.   PhonixReplace2(START , NewName, "PT"   , "T"    );
  479.   PhonixReplace2(START , NewName, "CZ"   , "C"    );
  480.   PhonixReplace1(MIDDLE, NewName, "WZ"   , "Z"    , VOC, NON);
  481.   PhonixReplace2(MIDDLE, NewName, "CZ"   , "CH"   );
  482.   PhonixReplace2(ALL   , NewName, "LZ"   , "LSH"  );
  483.   PhonixReplace2(ALL   , NewName, "RZ"   , "RSH"  );
  484.   PhonixReplace1(MIDDLE, NewName, "Z"    , "S"    , NON, VOC);
  485.   PhonixReplace2(ALL   , NewName, "ZZ"   , "TS"   );
  486.   PhonixReplace1(MIDDLE, NewName, "Z"    , "TS"   , CON, NON);
  487.   PhonixReplace2(ALL   , NewName, "HROUG", "REW"  );
  488.   PhonixReplace2(ALL   , NewName, "OUGH" , "OF"   );
  489.   PhonixReplace1(MIDDLE, NewName, "Q"    , "KW"   , VOC, VOC);
  490.   PhonixReplace1(MIDDLE, NewName, "J"    , "Y"    , VOC, VOC);
  491.   PhonixReplace1(START , NewName, "YJ"   , "Y"    , NON, VOC);
  492.   PhonixReplace2(START , NewName, "GH"   , "G"    );
  493.   PhonixReplace1(END   , NewName, "E"    , "GH"   , VOC, NON);
  494.   PhonixReplace2(START , NewName, "CY"   , "S"    );
  495.   PhonixReplace2(ALL   , NewName, "NX"   , "NKS"  );
  496.   PhonixReplace2(START , NewName, "PF"   , "F"    );
  497.   PhonixReplace2(END   , NewName, "DT"   , "T"    );
  498.   PhonixReplace2(END   , NewName, "TL"   , "TIL"  );
  499.   PhonixReplace2(END   , NewName, "DL"   , "DIL"  );
  500.   PhonixReplace2(ALL   , NewName, "YTH"  , "ITH"  );
  501.   PhonixReplace1(START , NewName, "TJ"   , "CH"   , NON, VOC);
  502.   PhonixReplace1(START , NewName, "TSJ"  , "CH"   , NON, VOC);
  503.   PhonixReplace1(START , NewName, "TS"   , "T"    , NON, VOC);
  504.   PhonixReplace1(ALL   , NewName, "TCH"  , "CH"   );
  505.   PhonixReplace1(MIDDLE, NewName, "WSK"  , "VSKIE", VOC, NON);
  506.   PhonixReplace1(END   , NewName, "WSK"  , "VSKIE", VOC, NON);
  507.   PhonixReplace1(START , NewName, "MN"   , "N"    , NON, VOC);
  508.   PhonixReplace1(START , NewName, "PN"   , "N"    , NON, VOC);
  509.   PhonixReplace1(MIDDLE, NewName, "STL"  , "SL"   , VOC, NON);
  510.   PhonixReplace1(END   , NewName, "STL"  , "SL"   , VOC, NON);
  511.   PhonixReplace2(END   , NewName, "TNT"  , "ENT"  );
  512.   PhonixReplace2(END   , NewName, "EAUX" , "OH"   );
  513.   PhonixReplace2(ALL   , NewName, "EXCI" , "ECS"  );
  514.   PhonixReplace2(ALL   , NewName, "X"    , "ECS"  );
  515.   PhonixReplace2(END   , NewName, "NED"  , "ND"   );
  516.   PhonixReplace2(ALL   , NewName, "JR"   , "DR"   );
  517.   PhonixReplace2(END   , NewName, "EE"   , "EA"   );
  518.   PhonixReplace2(ALL   , NewName, "ZS"   , "S"    );
  519.   PhonixReplace1(MIDDLE, NewName, "R"    , "AH"   , VOC, CON);
  520.   PhonixReplace1(END   , NewName, "R"    , "AH"   , VOC, NON); /* VOC,CON */
  521.   PhonixReplace1(MIDDLE, NewName, "HR"   , "AH"   , VOC, CON);
  522.   PhonixReplace1(END   , NewName, "HR"   , "AH"   , VOC, NON); /* VOC,CON */
  523.   PhonixReplace1(END   , NewName, "HR"   , "AH"   , VOC, NON);
  524.   PhonixReplace2(END   , NewName, "RE"   , "AR"   );
  525.   PhonixReplace1(END   , NewName, "R"    , "AH"   , VOC, NON);
  526.   PhonixReplace2(ALL   , NewName, "LLE"  , "LE"   );
  527.   PhonixReplace1(END   , NewName, "LE"   , "ILE"  , CON, NON);
  528.   PhonixReplace1(END   , NewName, "LES"  , "ILES" , CON, NON);
  529.   PhonixReplace2(END   , NewName, "E"    , ""     );
  530.   PhonixReplace2(END   , NewName, "ES"   , "S"    );
  531.   PhonixReplace1(END   , NewName, "SS"  , "AS"    , VOC, NON);
  532.   PhonixReplace1(END   , NewName, "MB"  , "M"     , VOC, NON);
  533.   PhonixReplace2(ALL   , NewName, "MPTS" , "MPS"  );
  534.   PhonixReplace2(ALL   , NewName, "MPS"  , "MS"   );
  535.   PhonixReplace2(ALL   , NewName, "MPT"  , "MT"   );
  536.  
  537.   /* calculate Key for NewName */
  538.   PhonixCode(NewName, Key);
  539.  
  540. #ifdef DEBUG
  541.   printf("NewName = %s\n", NewName);  
  542.   printf("Code    = %s\n\n", Key);  
  543. #endif /* DEBUG */
  544. }
  545.  
  546.  
  547. /****************************************************************************
  548. NAME    : Soundex
  549. INPUT   : char *Name --- string to calculate soundex code for
  550. OUTPUT  : char *Key  --- soundex code of Name
  551. FUNCTION: Soundex calculates the soundex code for the string Name.
  552. ****************************************************************************/
  553.  
  554. void Soundex (Name, Key)
  555. char *Name;
  556. char *Key;
  557. {
  558.   /* use new variable NewName to remain Name unchanged */
  559.   char NewName[50];
  560.   int  i; 
  561.  
  562.   strcpy(NewName, Name);
  563.  
  564.   /* uppercase NewName */
  565. #ifdef WIN32
  566.   for (i=0; i < (int)strlen(NewName); i++)
  567. #else
  568.   for (i=0; i < strlen(NewName); i++)
  569. #endif
  570.     if (islower(NewName[i])) 
  571.       NewName[i] = toupper(NewName[i]);
  572.  
  573.   /* calculate Key for Name */
  574.   SoundexCode(NewName, Key);
  575.   /* fprintf(stderr, "Soundex: %s -> %s\n", Name, Key); */
  576. }
  577.  
  578.  
  579. /****************************************************************************
  580. Now the two procedures PrintCode() and main() follow which will only be
  581. included if TEST is defined.
  582. ****************************************************************************/
  583.  
  584. #ifdef TEST
  585.  
  586. void PrintCode (Name)
  587. unsigned char *Name;
  588. {
  589.   unsigned char SoundexName[SoundexLen+1];
  590.   unsigned char PhonixName[PhonixLen+1];
  591.  
  592.   Soundex(Name, SoundexName);
  593.   Phonix(Name, PhonixName);
  594.   printf("%20s --> %s %s\n", Name, SoundexName, PhonixName);
  595. }
  596.  
  597.  
  598. void main ()
  599. {
  600.   unsigned char s[256];
  601.   PrintCode("CLASSEN");
  602.   PrintCode("WRITE");
  603.   PrintCode("WRIGHT");
  604.   PrintCode("RITE");
  605.   PrintCode("WHITE");
  606.   PrintCode("WAIT");
  607.   PrintCode("WEIGHT");
  608.   PrintCode("KNIGHT");
  609.   PrintCode("NIGHT");
  610.   PrintCode("NITE");
  611.   PrintCode("GNOME");
  612.   PrintCode("NOAM");
  613.   PrintCode("SMIDT");
  614.   PrintCode("SMITH");
  615.   PrintCode("SCHMIT");
  616.   PrintCode("CRAFT");
  617.   PrintCode("KRAFT");
  618.   PrintCode("REES");
  619.   PrintCode("REECE");
  620.   PrintCode("YAEGER");
  621.   PrintCode("YOGA");
  622.   PrintCode("EAGER");
  623.   PrintCode("AUGER");
  624.   PrintCode("Krueger");
  625.   PrintCode("Kruger");
  626.   PrintCode("Krⁿger");
  627.   while (1) {
  628.     PrintCode(gets(s));
  629.   }
  630. }
  631.  
  632. #endif /* TEST */
  633.