/****************************************************************************** Snippet: Soundex parser. Author: Richard Woolcock (aka KaVir). Date: 20th December 2000. ****************************************************************************** This code is copyright (C) 2000 by Richard Woolcock. It may be used and distributed freely, as long as you don't remove this copyright notice. ******************************************************************************/ /****************************************************************************** Required library files. ******************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "merc.h" /****************************************************************************** Local literals ******************************************************************************/ #define KEY_SIZE 4 /* Size of the soundex key */ /****************************************************************************** Local operation prototypes. ******************************************************************************/ static char LetterConversion ( char chLetter ); /****************************************************************************** Global operations. ******************************************************************************/ /* Function: GetSoundexKey * * This function determines a soundex key from the string argument and returns * the address of the key (which is stored in a static variable). Because the * most common use of the soundex key is to compare it with _another_ soundex * key, this function uses two internal storage buffers, which are alternated * between every time the function is called. * * The function takes one parameter, as follows: * * szTxt: A pointer to the string from which the soundex key is calculated. * * The return value is a pointer to the soundex key string. */ char *GetSoundexKey( const char *szTxt ) { int iOldIndex = 0; /* Loop index for the old (szTxt) string */ int iNewIndex = 0; /* Loop index for the new (s_a_chSoundex) string */ static char s_a_chSoundex[2][KEY_SIZE+1]; /* Stores the new string */ static unsigned iSoundex; /* Determines which s_a_chSoundex is used */ iSoundex++; /* Switch to the other s_a_chSoundex array */ s_a_chSoundex[iSoundex%2][0] = '\0'; /* Clear any previous data */ /* Copy the first character without conversion */ if ( ( s_a_chSoundex[iSoundex%2][iNewIndex++] = tolower(szTxt[iOldIndex++]) ) ) { do /* Loop through szTxt */ { char chLetter; /* Stores the soundex value of a letter */ /* Double/triple/etc letters are treated as single letters */ while ( tolower(szTxt[iOldIndex]) == tolower(szTxt[iOldIndex+1]) ) { iOldIndex++; continue; } /* Convert the letter into its soundex value and store it */ chLetter = LetterConversion((char)tolower(szTxt[iOldIndex])); /* Ignore NUL and 0 characters and only store KEY_SIZE characters */ if ( chLetter != '\0' && chLetter != '0' && iNewIndex < KEY_SIZE ) { /* Store the soundex value */ s_a_chSoundex[iSoundex%2][iNewIndex++] = chLetter; } } while ( szTxt[iOldIndex++] != '\0' ); /* If less than KEY_SIZE characters were copied, buffer with zeros */ while ( iNewIndex < KEY_SIZE ) { s_a_chSoundex[iSoundex%2][iNewIndex++] = '0'; } /* Add the NUL terminator to the end of the soundex string */ s_a_chSoundex[iSoundex%2][iNewIndex] = '\0'; } /* Return the address of the soundex string */ return ( s_a_chSoundex[iSoundex%2] ); } /* Function: SoundexMatch * * This function compares two soundex keys and returns a percentage match. * * The function takes two parameters, as follows: * * szFirst: A pointer to the first soundex key. * szSecond: A pointer to the second soundex key. * * The return value is an integer which contains the percentage match. */ int SoundexMatch( char *szFirst, char *szSecond ) { int iMatch = 0; /* Number of matching characters found */ int iMax = 0; /* Total number of characters compared */ /* Make sure that both strings are of the correct size */ if ( strlen( szFirst ) == KEY_SIZE && strlen( szSecond ) == KEY_SIZE ) { int i; /* Loop counter */ /* Loop through both strings */ for ( i = 0; i < KEY_SIZE; i++ ) { /* If either of the values are not NUL */ if ( szFirst[i] != '0' || szSecond[i] != '0' ) { iMax++; /* Increment the maximum */ } /* If BOTH values are not NUL */ if ( szFirst[i] != '0' && szSecond[i] != '0' ) { /* Check for a match */ if ( szFirst[i] == szSecond[i] ) { iMatch++; /* A match was found */ } } } } /* Return the percentage match */ return ( iMatch * 100 / iMax ); } /****************************************************************************** Local operations. ******************************************************************************/ /* Function: LetterConversion * * This function converts a single letter into it's appropriate soundex value. * * The function takes one parameter, as follows: * * chLetter: The letter to be converted. * * The return value is a single character which contains the converted value. */ static char LetterConversion( char chLetter ) { const char * kszSoundexData = "01230120022455012623010202"; char chResult; /* Store the soundex value, or NUL */ if ( islower(chLetter) ) { /* Determine the soundex value associated with the letter */ chResult = kszSoundexData[ (chLetter - 'a') ]; } else /* it's not a lowercase letter */ { /* NUL means there is no associated soundex value */ chResult = '\0'; } /* Return the soundex value, or NUL if there isn't one */ return ( chResult ); }