June 2018 Update
This commit is contained in:
parent
ba8067c3b7
commit
22f33d4004
5278 changed files with 84726 additions and 14379 deletions
|
|
@ -2,10 +2,10 @@ Soundex is an algorithm for creating indices for words based on their pronunciat
|
|||
|
||||
|
||||
;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 [[wp:soundex|the WP article]]).
|
||||
<br><br>
|
||||
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 [[wp:soundex|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 [[https://www.archives.gov/research/census/soundex.html]]. 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.
|
||||
<br><br>
|
||||
|
|
|
|||
77
Task/Soundex/C++/soundex.cpp
Normal file
77
Task/Soundex/C++/soundex.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include <iostream> // required for debug code in main() only
|
||||
#include <iomanip> // required for debug code in main() only
|
||||
#include <string>
|
||||
|
||||
std::string soundex( char const* s )
|
||||
{
|
||||
static char const code[] = { 0, -1, 1, 2, 3, -1, 1, 2, 0, -1, 2, 2, 4, 5, 5, -1, 1, 2, 6, 2, 3, -1, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0 };
|
||||
|
||||
if( !s || !*s )
|
||||
return std::string();
|
||||
|
||||
std::string out( "0000" );
|
||||
out[0] = (*s >= 'a' && *s <= 'z') ? *s - ('a' - 'A') : *s;
|
||||
++s;
|
||||
|
||||
char prev = code[out[0] & 0x1F]; // first letter, though not coded, can still affect next letter: Pfister
|
||||
for( unsigned i = 1; *s && i < 4; ++s )
|
||||
{
|
||||
if( (*s & 0xC0) != 0x40 ) // process only letters in range [0x40 - 0x7F]
|
||||
continue;
|
||||
auto const c = code[*s & 0x1F];
|
||||
if( c == prev )
|
||||
continue;
|
||||
|
||||
if( c == -1 )
|
||||
prev = 0; // vowel as separator
|
||||
else if( c )
|
||||
{
|
||||
out[i] = c + '0';
|
||||
++i;
|
||||
prev = c;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
static char const * const names[][2] =
|
||||
{
|
||||
{"Ashcraft", "A261"},
|
||||
{"Burroughs", "B620"},
|
||||
{"Burrows", "B620"},
|
||||
{"Ekzampul", "E251"},
|
||||
{"Ellery", "E460"},
|
||||
{"Euler", "E460"},
|
||||
{"Example", "E251"},
|
||||
{"Gauss", "G200"},
|
||||
{"Ghosh", "G200"},
|
||||
{"Gutierrez", "G362"},
|
||||
{"Heilbronn", "H416"},
|
||||
{"Hilbert", "H416"},
|
||||
{"Jackson", "J250"},
|
||||
{"Kant", "K530"},
|
||||
{"Knuth", "K530"},
|
||||
{"Ladd", "L300"},
|
||||
{"Lee", "L000"},
|
||||
{"Lissajous", "L222"},
|
||||
{"Lloyd", "L300"},
|
||||
{"Lukasiewicz", "L222"},
|
||||
{"O'Hara", "O600"},
|
||||
{"Pfister", "P236"},
|
||||
{"Soundex", "S532"},
|
||||
{"Sownteks", "S532"},
|
||||
{"Tymczak", "T522"},
|
||||
{"VanDeusen", "V532"},
|
||||
{"Washington", "W252"},
|
||||
{"Wheaton", "W350"}
|
||||
};
|
||||
|
||||
for( auto const& name : names )
|
||||
{
|
||||
auto const sdx = soundex( name[0] );
|
||||
std::cout << std::left << std::setw( 16 ) << name[0] << std::setw( 8 ) << sdx << (sdx == name[1] ? " ok" : " ERROR") << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
50
Task/Soundex/Julia/soundex.julia
Normal file
50
Task/Soundex/Julia/soundex.julia
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using Soundex
|
||||
@assert soundex("Ashcroft") == "A261" # true
|
||||
|
||||
# Too trivial? OK. Here is an example not using a package:
|
||||
function soundex(s)
|
||||
char2num = Dict('B'=>1,'F'=>1,'P'=>1,'V'=>1,'C'=>2,'G'=>2,'J'=>2,'K'=>2,
|
||||
'Q'=>2,'S'=>2,'X'=>2,'Z'=>2,'D'=>3,'T'=>3,'L'=>4,'M'=>5,'N'=>5,'R'=>6)
|
||||
s = replace(s, r"[^a-zA-Z]", "")
|
||||
if s == ""
|
||||
return ""
|
||||
end
|
||||
ret = "$(uppercase(s[1]))"
|
||||
hadvowel = false
|
||||
lastletternum = haskey(char2num, ret[1]) ? char2num[ret[1]] : ""
|
||||
for c in s[2:end]
|
||||
c = uppercase(c)
|
||||
if haskey(char2num, c)
|
||||
letternum = char2num[c]
|
||||
if letternum != lastletternum || hadvowel
|
||||
ret = "$ret$letternum"
|
||||
lastletternum = letternum
|
||||
hadvowel = false
|
||||
end
|
||||
elseif c in ('A', 'E', 'I', 'O', 'U', 'Y')
|
||||
hadvowel = true
|
||||
end
|
||||
end
|
||||
while length(ret) < 4
|
||||
ret *= "0"
|
||||
end
|
||||
ret[1:4]
|
||||
end
|
||||
@assert soundex("Ascroft") == "A261"
|
||||
@assert soundex("Euler") == "E460"
|
||||
@assert soundex("Gausss") == "G200"
|
||||
@assert soundex("Hilbert") == "H416"
|
||||
@assert soundex("Knuth") == "K530"
|
||||
@assert soundex("Lloyd") == "L300"
|
||||
@assert soundex("Lukasiewicz") == "L222"
|
||||
@assert soundex("Ellery") == "E460"
|
||||
@assert soundex("Ghosh") == "G200"
|
||||
@assert soundex("Heilbronn") == "H416"
|
||||
@assert soundex("Kant") == "K530"
|
||||
@assert soundex("Ladd") == "L300"
|
||||
@assert soundex("Lissajous") == "L222"
|
||||
@assert soundex("Wheaton") == "W350"
|
||||
@assert soundex("Ashcraft") == "A261"
|
||||
@assert soundex("Burroughs") == "B620"
|
||||
@assert soundex("Burrows") == "B620"
|
||||
@assert soundex("O'Hara") == "O600"
|
||||
42
Task/Soundex/Lua/soundex.lua
Normal file
42
Task/Soundex/Lua/soundex.lua
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
local d, digits, alpha = '01230120022455012623010202', {}, ('A'):byte()
|
||||
d:gsub(".",function(c)
|
||||
digits[string.char(alpha)] = c
|
||||
alpha = alpha + 1
|
||||
end)
|
||||
|
||||
function soundex(w)
|
||||
local res = {}
|
||||
for c in w:upper():gmatch'.'do
|
||||
local d = digits[c]
|
||||
if d then
|
||||
if #res==0 then
|
||||
res[1] = c
|
||||
elseif #res==1 or d~= res[#res] then
|
||||
res[1+#res] = d
|
||||
end
|
||||
end
|
||||
end
|
||||
if #res == 0 then
|
||||
return '0000'
|
||||
else
|
||||
res = table.concat(res):gsub("0",'')
|
||||
return (res .. '0000'):sub(1,4)
|
||||
end
|
||||
end
|
||||
|
||||
-- tests
|
||||
local tests = {
|
||||
{"", "0000"}, {"12346", "0000"},
|
||||
{"he", "H000"}, {"soundex", "S532"},
|
||||
{"example", "E251"}, {"ciondecks", "C532"},
|
||||
{"ekzampul", "E251"}, {"résumé", "R250"},
|
||||
{"Robert", "R163"}, {"Rupert", "R163"},
|
||||
{"Rubin", "R150"}, {"Ashcraft", "A226"},
|
||||
{"Ashcroft", "A226"}
|
||||
}
|
||||
|
||||
for i=1,#tests do
|
||||
local itm = tests[i]
|
||||
assert( soundex(itm[1])==itm[2] )
|
||||
end
|
||||
print"all tests ok"
|
||||
103
Task/Soundex/NetRexx/soundex.netrexx
Normal file
103
Task/Soundex/NetRexx/soundex.netrexx
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
class Soundex
|
||||
|
||||
method get_soundex(in_) static
|
||||
in = in_.upper()
|
||||
old_alphabet= 'AEIOUYHWBFPVCGJKQSXZDTLMNR'
|
||||
new_alphabet= '@@@@@@**111122222222334556'
|
||||
word=''
|
||||
loop i=1 for in.length()
|
||||
tmp_=in.substr(i, 1) /*obtain a character from word*/
|
||||
if tmp_.datatype('M') then word=word||tmp_
|
||||
end
|
||||
|
||||
value=word.strip.left(1) /*1st character is left alone.*/
|
||||
word=word.translate(new_alphabet, old_alphabet) /*define the current word. */
|
||||
prev=value.translate(new_alphabet, old_alphabet) /* " " previous " */
|
||||
|
||||
loop j=2 to word.length() /*process remainder of word. */
|
||||
q=word.substr(j, 1)
|
||||
if q\==prev & q.datatype('W') then do
|
||||
value=value || q; prev=q
|
||||
end
|
||||
else if q=='@' then prev=q
|
||||
end /*j*/
|
||||
|
||||
return value.left(4,0) /*padded value with zeroes. */
|
||||
|
||||
method main(args=String[]) static
|
||||
|
||||
test=''; result_=''
|
||||
test['1']= "12346" ; result_['1']= '0000'
|
||||
test['4']= "4-H" ; result_['4']= 'H000'
|
||||
test['11']= "Ashcraft" ; result_['11']= 'A261'
|
||||
test['12']= "Ashcroft" ; result_['12']= 'A261'
|
||||
test['18']= "auerbach" ; result_['18']= 'A612'
|
||||
test['20']= "Baragwanath" ; result_['20']= 'B625'
|
||||
test['22']= "bar" ; result_['22']= 'B600'
|
||||
test['23']= "barre" ; result_['23']= 'B600'
|
||||
test['20']= "Baragwanath" ; result_['20']= 'B625'
|
||||
test['28']= "Burroughs" ; result_['28']= 'B620'
|
||||
test['29']= "Burrows" ; result_['29']= 'B620'
|
||||
test['30']= "C.I.A." ; result_['30']= 'C000'
|
||||
test['37']= "coöp" ; result_['37']= 'C100'
|
||||
test['43']= "D-day" ; result_['43']= 'D000'
|
||||
test['44']= "d jay" ; result_['44']= 'D200'
|
||||
test['45']= "de la Rosa" ; result_['45']= 'D462'
|
||||
test['46']= "Donnell" ; result_['46']= 'D540'
|
||||
test['47']= "Dracula" ; result_['47']= 'D624'
|
||||
test['48']= "Drakula" ; result_['48']= 'D624'
|
||||
test['49']= "Du Pont" ; result_['49']= 'D153'
|
||||
test['50']= "Ekzampul" ; result_['50']= 'E251'
|
||||
test['51']= "example" ; result_['51']= 'E251'
|
||||
test['55']= "Ellery" ; result_['55']= 'E460'
|
||||
test['59']= "Euler" ; result_['59']= 'E460'
|
||||
test['60']= "F.B.I." ; result_['60']= 'F000'
|
||||
test['70']= "Gauss" ; result_['70']= 'G200'
|
||||
test['71']= "Ghosh" ; result_['71']= 'G200'
|
||||
test['72']= "Gutierrez" ; result_['72']= 'G362'
|
||||
test['80']= "he" ; result_['80']= 'H000'
|
||||
test['81']= "Heilbronn" ; result_['81']= 'H416'
|
||||
test['84']= "Hilbert" ; result_['84']= 'H416'
|
||||
test['100']= "Jackson" ; result_['100']= 'J250'
|
||||
test['104']= "Johnny" ; result_['104']= 'J500'
|
||||
test['105']= "Jonny" ; result_['105']= 'J500'
|
||||
test['110']= "Kant" ; result_['110']= 'K530'
|
||||
test['116']= "Knuth" ; result_['116']= 'K530'
|
||||
test['120']= "Ladd" ; result_['120']= 'L300'
|
||||
test['124']= "Llyod" ; result_['124']= 'L300'
|
||||
test['125']= "Lee" ; result_['125']= 'L000'
|
||||
test['126']= "Lissajous" ; result_['126']= 'L222'
|
||||
test['128']= "Lukasiewicz" ; result_['128']= 'L222'
|
||||
test['130']= "naïve" ; result_['130']= 'N100'
|
||||
test['141']= "Miller" ; result_['141']= 'M460'
|
||||
test['143']= "Moses" ; result_['143']= 'M220'
|
||||
test['146']= "Moskowitz" ; result_['146']= 'M232'
|
||||
test['147']= "Moskovitz" ; result_['147']= 'M213'
|
||||
test['150']= "O'Conner" ; result_['150']= 'O256'
|
||||
test['151']= "O'Connor" ; result_['151']= 'O256'
|
||||
test['152']= "O'Hara" ; result_['152']= 'O600'
|
||||
test['153']= "O'Mally" ; result_['153']= 'O540'
|
||||
test['161']= "Peters" ; result_['161']= 'P362'
|
||||
test['162']= "Peterson" ; result_['162']= 'P362'
|
||||
test['165']= "Pfister" ; result_['165']= 'P236'
|
||||
test['180']= "R2-D2" ; result_['180']= 'R300'
|
||||
test['182']= "rÄ≈sumÅ∙" ; result_['182']= 'R250'
|
||||
test['184']= "Robert" ; result_['184']= 'R163'
|
||||
test['185']= "Rupert" ; result_['185']= 'R163'
|
||||
test['187']= "Rubin" ; result_['187']= 'R150'
|
||||
test['191']= "Soundex" ; result_['191']= 'S532'
|
||||
test['192']= "sownteks" ; result_['192']= 'S532'
|
||||
test['199']= "Swhgler" ; result_['199']= 'S460'
|
||||
test['202']= "'til" ; result_['202']= 'T400'
|
||||
test['208']= "Tymczak" ; result_['208']= 'T522'
|
||||
test['216']= "Uhrbach" ; result_['216']= 'U612'
|
||||
test['221']= "Van de Graaff" ; result_['221']= 'V532'
|
||||
test['222']= "VanDeusen" ; result_['222']= 'V532'
|
||||
test['230']= "Washington" ; result_['230']= 'W252'
|
||||
test['233']= "Wheaton" ; result_['233']= 'W350'
|
||||
test['234']= "Williams" ; result_['234']= 'W452'
|
||||
test['236']= "Woolcock" ; result_['236']= 'W422'
|
||||
|
||||
loop i over test
|
||||
say test[i].left(10) get_soundex(test[i]) '=' result_[i]
|
||||
end
|
||||
18
Task/Soundex/PowerShell/soundex-3.psh
Normal file
18
Task/Soundex/PowerShell/soundex-3.psh
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# script Soundex.ps1
|
||||
Param([string]$Phrase)
|
||||
Process {
|
||||
$src = $Phrase.ToUpper().Trim()
|
||||
$coded = $src[0..($src.Length - 1)] | %{
|
||||
if('BFPV'.Contains($_)) { '1' }
|
||||
elseif('CGJKQSXZ'.Contains($_)) { '2' }
|
||||
elseif('DT'.Contains($_)) { '3' }
|
||||
elseif('L'.Contains($_)) { '4' }
|
||||
elseif('MN'.Contains($_)) { '5' }
|
||||
elseif('R'.Contains($_)) { '6' }
|
||||
elseif('AEIOU'.Contains($_)) { 'v' }
|
||||
else { '.' }
|
||||
} | Where { $_ -ne '.'}
|
||||
$coded2 = 0..($coded.Length - 1) | %{ if ($_ -eq 0 -or $coded[$_] -ne $coded[$_ - 1]) { $coded[$_] } else { '' } }
|
||||
$coded2 = if ($coded[0] -eq 'v' -or $coded2[0] -ne $coded[0]) { $coded2 } else { $coded2[1..($coded2.Length - 1)] }
|
||||
$src[0] + ((-join $($coded2 | Where { $_ -ne 'v'})) + "000").Substring(0,3)
|
||||
}
|
||||
15
Task/Soundex/PowerShell/soundex-4.psh
Normal file
15
Task/Soundex/PowerShell/soundex-4.psh
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Function t([string]$value, [string]$expect) {
|
||||
$result = .\Soundex.ps1 -Phrase $value
|
||||
New-Object –TypeName PSObject –Prop @{ "Value"=$value; "Expect"=$expect; "Result"=$result; "Pass"=$($expect -eq $result) }
|
||||
}
|
||||
@(
|
||||
(t "Ashcraft" "A261"); (t "Ashcroft" "A261"); (t "Burroughs" "B620"); (t "Burrows" "B620");
|
||||
(t "Ekzampul" "E251"); (t "Example" "E251"); (t "Ellery" "E460"); (t "Euler" "E460");
|
||||
(t "Ghosh" "G200"); (t "Gauss" "G200"); (t "Gutierrez" "G362"); (t "Heilbronn" "H416");
|
||||
(t "Hilbert" "H416"); (t "Jackson" "J250"); (t "Kant" "K530"); (t "Knuth" "K530");
|
||||
(t "Lee" "L000"); (t "Lukasiewicz" "L222"); (t "Lissajous" "L222"); (t "Ladd" "L300");
|
||||
(t "Lloyd" "L300"); (t "Moses" "M220"); (t "O'Hara" "O600"); (t "Pfister" "P236");
|
||||
(t "Rubin" "R150"); (t "Robert" "R163"); (t "Rupert" "R163"); (t "Soundex" "S532");
|
||||
(t "Sownteks" "S532"); (t "Tymczak" "T522"); (t "VanDeusen" "V532"); (t "Washington" "W252");
|
||||
(t "Wheaton" "W350");
|
||||
) | Format-Table -Property Value,Expect,Result,Pass
|
||||
23
Task/Soundex/Ring/soundex.ring
Normal file
23
Task/Soundex/Ring/soundex.ring
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Project: Soundex
|
||||
# Date : 2018/06/11
|
||||
# Author: Gal Zsolt [~ CalmoSoft ~]
|
||||
# Email : <calmosoft@gmail.com>
|
||||
|
||||
name = ["Ashcraf", "Ashcroft", "Gauss", "Ghosh", "Hilbert", "Heilbronn", "Lee", "Lloyd",
|
||||
"Moses", "Pfister", "Robert", "Rupert", "Rubin","Tymczak", "Soundex", "Example"]
|
||||
for i = 1 to 16
|
||||
sp = 10 - len(name[i])
|
||||
see '"' + name[i] + '"' + copy(" ", sp) + " " + soundex(name[i]) + nl
|
||||
next
|
||||
|
||||
func soundex(name2)
|
||||
name2 = upper(name2)
|
||||
n = "01230129022455012623019202"
|
||||
s = left(name2,1)
|
||||
p = number(substr(n, ascii(s) - 64, 1))
|
||||
for i = 2 to len(name2)
|
||||
n2 = number(substr(n, ascii(name2[i]) - 64, 1))
|
||||
if n2 > 0 and n2 != 9 and n2 != p s = s + string(n2) ok
|
||||
if n2 != 9 p = n2 ok
|
||||
next
|
||||
return left(s + "000", 4)
|
||||
2
Task/Soundex/Stata/soundex-2.stata
Normal file
2
Task/Soundex/Stata/soundex-2.stata
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
. di soundex("Ashcraft")
|
||||
A226
|
||||
Loading…
Add table
Add a link
Reference in a new issue