Soundex is an algorithm for creating indices for words based on their pronunciation.



Task

The goal is for homophones to be encoded to the same representation so that they can be matched despite minor differences in spelling   (from the   soundex   Wikipedia article).

Caution

There is a major issue in many of the implementations concerning the separation of two consonants that have the same soundex code! According to the official Rules [[1]]. So check for instance if Ashcraft is coded to A-261.

 If a vowel (A, E, I, O, U) separates two consonants that have the same soundex code, the consonant to the right of the vowel is coded. Tymczak is coded as T-522 (T, 5 for the M, 2 for the C, Z ignored (see "Side-by-Side" rule above), 2 for the K). Since the vowel "A" separates the Z and K, the K is coded.
 If "H" or "W" separate two consonants that have the same soundex code, the consonant to the right of the vowel is not coded. Example: Ashcraft is coded A-261 (A, 2 for the S, C ignored, 6 for the R, 1 for the F). It is not coded A-226.


include "NSLog.incl"
 
local fn SoundexCode( charCode as unsigned char ) as unsigned char
  select charCode
    case _"B", _"F", _"P", _"V"
      charCode = _"1"
    case _"C", _"G", _"J", _"K", _"Q", _"S", _"X", _"Z"
      charCode = _"2"
    case _"D", _"T"
      charCode = _"3"
    case _"L"
      charCode = _"4"
    case _"M", _"N"
      charCode = _"5"
    case _"R"
      charCode = _"6"
    case else
      charCode = 0
  end select
end fn = charCode
 
local fn SoundexCodeForWord( codeWord as CFStringRef ) as CFStringRef
  NSUInteger         i
  unsigned char      charCode, lastCode
  CFStringRef        outputStr = @"0000"
  CFMutableStringRef tempStr
 
  if ( len(codeWord) == 0 ) then exit fn
 
  tempStr = fn MutableStringWithCapacity(0)
  codeWord = ucase(fn StringByApplyingTransform( codeWord, NSStringTransformStripDiacritics, NO ))
 
  MutableStringAppendString( tempStr, left(codeWord,1) )
  charCode = fn StringCharacterAtIndex( codeWord, 0 )
  charCode = fn SoundexCode( charCode )
  lastCode = charCode
  i = 0
  while i < len(codeWord) - 1
    i++
    charCode = fn StringCharacterAtIndex( codeWord, i )
    charCode = fn SoundexCode( charCode )
    if ( charCode > 0 and lastCode != charCode )
      MutableStringAppendString( tempStr, fn StringWithFormat( @"%c",charCode ) )
      if ( len(tempStr) == 4 ) then break
    end if
    lastCode = charCode
  wend
 
  while ( len(tempStr) < 4 )
    MutableStringAppendString( tempStr, @"0" )
  wend
 
  outputStr = fn StringWithString( tempStr )
end fn = outputStr
 
CFArrayRef  names
CFStringRef name
 
names = @[
@"Smith",@"Johnson",@"Williams",@"Jones",@"Brown",@"Davis",@"Miller",@"Wilson",@"Moore",@"Taylor",
@"Anderson",@"Thomas",@"Jackson",@"White",@"Harris",@"Martin",@"Thompson",@"Garcia",@"Martinez",@"Robinson",
@"Clark",@"Rodriguez",@"Lewis",@"Lee",@"Walker",@"Hall",@"Allen",@"Young",@"Hernandez",@"King",
@"Wright",@"Lopez",@"Hill",@"Scott",@"Green",@"Adams",@"Baker",@"Gonzalez",@"Nelson",@"Carter",
@"Mitchell",@"Perez",@"Roberts",@"Turner",@"Phillips",@"Campbell",@"Parker",@"Evans",@"Edwards",@"Collins",
@"Stewart",@"Sanchez",@"Morris",@"Rogers",@"Reed",@"Cook",@"Morgan",@"Bell",@"Murphy",@"Bailey",
@"Rivera",@"Cooper",@"Richardson",@"Cox",@"Howard",@"Ward",@"Torres",@"Peterson",@"Gray",@"Ramirez",
@"James",@"Watson",@"Brooks",@"Kelly",@"Sanders",@"Price",@"Bennett",@"Wood",@"Barnes",@"Ross",
@"Henderson",@"Coleman",@"Jenkins",@"Perry",@"Powell",@"Long",@"Patterson",@"Hughes",@"Flores",@"Washington",
@"Butler",@"Simmons",@"Foster",@"Gonzales",@"Bryant",@"Alexander",@"Russell",@"Griffin",@"Diaz",@"Hayes"
]
 
NSLogSetTabInterval( 80 )
NSLog( @"Soundex codes for %ld popular American surnames:",fn ArrayCount(names) )
for name in names
  NSLog( @"%@\t= %@",name,fn SoundexCodeForWord(name) )
next
 
NSLog(@"")
 
NSLog( @"Soundex codes for similar sounding names:" )
NSLog( @"Stuart\t= %@" , fn SoundexCodeForWord( @"Stuart"  ) )
NSLog( @"Stewart\t= %@", fn SoundexCodeForWord( @"Stewart" ) )
NSLog( @"Steward\t= %@", fn SoundexCodeForWord( @"Steward" ) )
NSLog( @"Seward\t= %@" , fn SoundexCodeForWord( @"Seward"  ) )
 
HandleEvents