Legacy:DoubleMetaPhone - Unreal Wiki

# Legacy:DoubleMetaPhone

### From Unreal Wiki, The Unreal Engine Documentation Site

This document implements a "sounds like" algorithm developed by Lawrence Philips which he published in the June, 2000 issue of C/C++ Users Journal.

Double Metaphone is an improved version of Philips' original Metaphone algorithm.

The UnrealScript implementation has been adapted from Stephen Woodbridge's PHP implementation by El Muerte.

Note: Because of the size of the algorithm there might be errors in it.

## The algorithm

    /**
            Returns the double metaphone value of in.
            The array always contains two values.
    */
    static final function array<string> DoubleMetaPhone(coerce string in, optional int mlen)
    {
            local array<string> res;
            local string prim, sec, tmp;
            local int cur, last, slen;

            if (mlen == 0) mlen = 4;
            slen = Len(in);
            last = slen-1;
            in = caps(in$"     ");
            // skip this at beginning of word
            switch (Left(in, 2))
            {
                    case "GN":
                    case "KN":
                    case "PN":
                    case "WR":
                    case "PS":
                            cur++;
            }
            // Initial 'X' is pronounced 'Z' e.g. 'Xavier'
            if (Left(in, 1) == "X")
            {
                    prim $= "S"; // 'Z' maps to 'S'
                    sec  $= "S";
                    cur++;
            }
            // main loop
            while (len(prim) < mlen || len(sec) < mlen)
            {
                    if (cur >= slen) break;
                    switch (mid(in, cur, 1))
                    {
                            case "A":
                            case "E":
                            case "I":
                            case "O":
                            case "U":
                            case "Y":
                                    if (cur == 0) // all init vowels now map to 'A'
                                    {
                                            prim $= "A";
                                            sec      $= "A";
                                    }
                                    cur++;
                                    break;

                            case "B": // '-mb', e.g. "dumb", already skipped over ...
                                    prim $= "P";
                                    sec  $= "P";
                                    if (mid(in, cur+1, 1) == "B") cur += 2;
                                    else cur++;
                                    break;

                            case "Ç":
                                    prim $= "S";
                                    sec  $= "S";
                                    cur++;
                                    break;

                            case "C": // various gremanic
                                    if ((cur > 1)
                                            && (!is_vowel(in, cur-2))
                                            && (mid(in, cur - 1, 3) == "ACH")
                                            && ((mid(in, cur + 2, 1) != "I")
                                                    && ((mid(in, cur + 2, 1) != "E")
                                                            || smid(in, cur - 2, 6, tmp) == "BACHER")
                                                            || tmp == "MACHER"))
                                    {
                                            prim $= "K";
                                            sec  $= "K";
                                            cur += 2;
                                            break;
                                    }

                                    // special case 'caesar'
                                    if ((cur == 0) && (mid(in, cur, 6) == "CAESAR"))
                                    {
                                            prim $= "S";
                                            sec  $= "S";
                                            cur += 2;
                                            break;
                                    }

                                    // italian 'chianti'
                                    if (mid(in, cur, 4) == "CHIA")
                                    {
                                            prim $= "K";
                                            sec  $= "K";
                                            cur += 2;
                                            break;
                                    }

                                    if (mid(in, cur, 2) == "CH")
                                    {
                                            // find 'michael'
                                            if ((cur > 0) && (mid(in, cur, 4) == "CHAE"))
                                            {
                                                    prim $= "K";
                                                    sec  $= "X";
                                                    cur += 2;
                                                    break;
                                            }

                                            // greek roots e.g. 'chemistry', 'chorus'
                                            if ((cur == 0)
                                                    && (smid(in, cur+1, 5, tmp) == "HARAC"
                                                            || tmp == "HARIS")
                                                    || (smid(in, cur+1, 3, tmp) == "HOR"
                                                            || tmp == "HYM"
                                                            || tmp == "HIA"
                                                            || tmp == "HEM")
                                                    && (mid(in, 0, 5) != "CHORE"))
                                            {
                                                    prim $= "K";
                                                    sec  $= "K";
                                                    cur += 2;
                                                    break;
                                            }

                                            // germanic, greek, or otherwise 'ch' for 'kh' sound
                                            if ((        (smid(in, 0, 4, tmp) == "VAN ")
                                                            || (tmp == "VON ")
                                                            || (tmp == "SCH")
                                                    )
                                                    // 'architect' but not 'arch', orchestra', 'orchid'
                                                    || (       (smid(in, cur-2, 6, tmp) == "ORCHES")
                                                                    || (tmp == "ARCHIT")
                                                                    || (tmp == "ORCHID")
                                                            )
                                                    || (InStr("TS", Mid(in, cur+2, 1)) > -1)
                                                    || (
                                                            ((InStr("AOUE", Mid(in, cur-1, 1)) > -1)
                                                                    || (cur == 0)
                                                            )
                                                            // e.g. 'wachtler', 'weschsler', but not 'tichner'
                                                            && (InStr("LRNMBHFVW", Mid(in, cur+2, 1)) > -1))
                                                    )
                                            {
                                                    prim $= "K";
                                                    sec  $= "K";
                                            }
                                            else {
                                                    if (cur > 0)
                                                    {
                                                            if (mid(in, 0, 2) == "MC")
                                                            {
                                                                    // e.g. 'McHugh'
                                                                    prim $= "K";
                                                                    sec  $= "K";
                                                            }
                                                            else {
                                                                    prim $= "X";
                                                                    sec  $= "K";
                                                            }
                                                    }
                                                    else {
                                                            prim $= "X";
                                                            sec  $= "X";
                                                    }
                                            }
                                            cur += 2;
                                            break;
                                    }

                                    // e.g. 'czerny'
                                    if (mid(in, cur, 2) == "CZ"
                                            && mid(in, cur-2, 4) != "WICZ")
                                    {
                                            prim $= "S";
                                            sec  $= "X";
                                            cur += 2;
                                            break;
                                    }

                                    // e.g. 'focaccia'
                                    if (mid(in, cur + 1, 3) == "CIA")
                                    {
                                            prim $= "X";
                                            sec  $= "X";
                                            cur += 3;
                                            break;
                                    }

                                    // double 'C', but not McClellan'
                                    if (mid(in, cur, 2) == "CC"
                                                    && !((cur == 1)
                                                            && (mid(in, 0, 1) == "M")))
                                    {
                                            // 'bellocchio' but not 'bacchus'
                                            if ((InStr("IEH", mid(in, cur + 2, 1)) > -1)
                                                    && (mid(in, cur + 2, 2) != "HU"))
                                            {
                                                    // 'accident', 'accede', 'succeed'
                                                    if (((cur == 1)
                                                            && (mid(in, cur - 1, 1) == "A"))
                                                            || (smid(in, cur-1, 5, tmp) == "UCCEE")
                                                            || (tmp == "UCCES"))
                                                    {
                                                            prim $= "KS";
                                                            sec  $= "KS";
                                                            // 'bacci', 'bertucci', other italian
                                                    }
                                                    else {
                                                            prim $= "X";
                                                            sec  $= "X";
                                                    }
                                                    cur += 3;
                                                    break;
                                            }
                                            else {
                                                    // Pierce's rule
                                                    prim $= "K";
                                                    sec $= "K";
                                                    cur += 2;
                                                    break;
                                            }
                                    }

                                    if ((smid(in, cur, 2, tmp) == "CK")
                                            || (tmp == "CG")
                                            || (tmp == "CQ"))
                                    {
                                            prim $= "K";
                                            sec  $= "K";
                                            cur += 2;
                                            break;
                                    }

                                    if ((smid(in, cur, 2, tmp) == "CI")
                                            || (tmp == "CE")
                                            || (tmp == "CY"))
                                    {
                                            // italian vs. english
                                            if ((smid(in, cur, 3, tmp) == "CIO")
                                                    || (tmp == "CIE")
                                                    || (tmp == "CIA"))
                                            {
                                                    prim $= "S";
                                                    sec  $= "X";
                                            }
                                            else {
                                                    prim $= "S";
                                                    sec  $= "S";
                                            }
                                            cur += 2;
                                            break;
                                    }

                                    // else
                                    prim $= "K";
                                    sec  $= "K";

                                    // name sent in 'mac caffrey', 'mac gregor'
                                    if ((smid(in, cur+1, 2, tmp) == " C")
                                            || (tmp == " Q")
                                            || (tmp == " G"))
                                    {
                                            cur += 3;
                                    }
                                    else {
                                            if ((InStr("CKQ", mid(in, cur + 1, 1)) > -1)
                                                    && !((smid(in, cur+1, 2, tmp) == "CE")
                                                            || (tmp == "CI"))
                                                    )
                                            {
                                                    cur += 2;
                                            }
                                            else {
                                                    cur++;
                                            }
                                    }
                                    break;

                            case "D":
                                    if (mid(in, cur, 2) == "DG")
                                    {
                                            if (InStr("IEY", mid(in, cur + 2, 1)) > -1)
                                            {
                                                    // e.g. 'edge'
                                                    prim $= "J";
                                                    sec  $= "J";
                                                    cur += 3;
                                                    break;
                                            }
                                            else {
                                                    // e.g. 'edgar'
                                                    prim $= "TK";
                                                    sec  $= "TK";
                                                    cur += 2;
                                                    break;
                                            }
                                    }

                                    if ((smid(in, cur, 2, tmp) == "DT")
                                            || (tmp == "DD"))
                                    {
                                            prim $= "T";
                                            sec  $= "T";
                                            cur += 2;
                                            break;
                                    }

                                    // else
                                    prim $= "T";
                                    sec  $= "T";
                                    cur++;
                                    break;

                            case "F":
                                    if (mid(in, cur + 1, 1) == "F") cur += 2;
                                    else cur++;
                                    prim $= "F";
                                    sec  $= "F";
                                    break;

                            // TODO: optimize
                            case "G":
                                    if (mid(in, cur + 1, 1) == "H")
                                    {
                                            if ((cur > 0) && !is_vowel(in, cur-1))
                                            {
                                                    prim $= "K";
                                                    sec  $= "K";
                                                    cur += 2;
                                                    break;
                                            }

                                            if (cur < 3)
                                            {
                                                    // 'ghislane', 'ghiradelli'
                                                    if (cur == 0)
                                                    {
                                                            if (mid(in, cur + 2, 1) == "I")
                                                            {
                                                                    prim $= "J";
                                                                    sec  $= "J";
                                                            }
                                                            else {
                                                                    prim $= "K";
                                                                    sec  $= "K";
                                                            }
                                                            cur += 2;
                                                            break;
                                                    }
                                            }

                                            // Parker's rule (with some further refinements) - e.g. 'hugh'
                                            if (((cur > 1) && (InStr("BHD", mid(in, cur - 2, 1)) > -1))
                                                    // e.g. 'bough'
                                                    || ((cur > 2) && (InStr("BHD", mid(in, cur - 3, 1)) > -1))
                                                    // e.g. 'broughton'
                                                    || ((cur > 3) && (InStr("BH", mid(in, cur - 4, 1)) > -1)))
                                            {
                                                    cur += 2;
                                                    break;
                                            }
                                            else {
                                                    // e.g. 'laugh', 'McLaughlin', 'cough', 'gough', 'rough', 'tough'
                                                    if ((cur > 2)
                                                            && (Mid(in, cur - 1, 1) == "U")
                                                            && (InStr("CGLRT", mid(in, cur - 3, 1)) > -1))
                                                    {
                                                            prim $= "F";
                                                            sec  $= "F";
                                                    }
                                                    else {
                                                            if ((cur > 0) && mid(in, cur - 1, 1) != "I")
                                                            {
                                                                    prim $= "K";
                                                                    sec  $= "K";
                                                            }
                                                            cur += 2;
                                                            break;
                                                    }
                                            }
                                    }

                                    if (mid(in, cur + 1, 1) == "N")
                                    {
                                            if ((cur == 1) && is_vowel(in, 0) && !Slavo_Germanic(in))
                                            {
                                                    prim $= "KN";
                                                    sec  $= "N";
                                            }
                                            else {
                                                    // not e.g. 'cagney'
                                                    if ((mid(in, cur + 2, 2) != "EY")
                                                            && (mid(in, cur + 1) != "Y")
                                                            && !Slavo_Germanic(in))
                                                    {
                                                            prim $= "N";
                                                            sec  $= "KN";
                                                    }
                                                    else {
                                                            prim $= "KN";
                                                            sec  $= "KN";
                                                    }
                                            }
                                            cur += 2;
                                            break;
                                    }

                                    // 'tagliaro'
                                    if ((mid(in, cur + 1, 2) == "LI") && !Slavo_Germanic(in))
                                    {
                                            prim $= "KL";
                                            sec  $= "L";
                                            cur += 2;
                                            break;
                                    }

                                    // -ges-, -gep-, -gel- at beginning
                                    if ((cur == 0)
                                            && ((mid(in, cur + 1, 1) == "Y")
                                                    || ((smid(in, cur + 1, 2, tmp) == "ES")
                                                            || (tmp == "EP")
                                                            || (tmp == "EB")
                                                            || (tmp == "EL")
                                                            || (tmp == "EY")
                                                            || (tmp == "IB")
                                                            || (tmp == "IL")
                                                            || (tmp == "IN")
                                                            || (tmp == "IE")
                                                            || (tmp == "EI")
                                                            || (tmp == "ER"))
                                                    )
                                            )
                                    {
                                            prim $= "K";
                                            sec  $= "J";
                                            cur += 2;
                                            break;
                                    }

                                    // -ger-, -gy-
                                    if (((mid(in, cur + 1, 2) == "ER")
                                            || (mid(in, cur + 1, 1) == "Y"))
                                            && !(smid(in, 0, 6, tmp) == "DANGER"
                                                    || tmp == "RANGER"
                                                    || tmp == "MANGER"
                                            )
                                            && (InStr("EI", mid(in, cur-1, 1)) == -1)
                                            && !(smid(in, cur-1, 3, tmp) == "RGY"
                                                    || tmp == "OGY"
                                            ))
                                    {
                                            prim $= "K";
                                            sec  $= "J";
                                            cur += 2;
                                            break;
                                    }

                                    // italian e.g. 'biaggi'
                                    if ((InStr("EIY", mid(in, cur + 1, 1)) > -1)
                                            || smid(in, cur-1, 4, tmp) == "AGGI"
                                            || tmp == "OGGI")
                                    {
                                            // obvious germanic
                                            if (((smid(in, 0, 4, tmp) == "VAN "
                                                            || tmp == "VON ")
                                                    || (mid(in, 0, 3) == "SCH"))
                                                    || (mid(in, cur + 1, 2) == "ET"))
                                            {
                                                    prim $= "K";
                                                    sec  $= "K";
                                            }
                                            else {
                                                    // always soft if french ending
                                                    if (mid(in, cur + 1, 4) == "IER ")
                                                    {
                                                            prim $= "J";
                                                            sec  $= "J";
                                                    }
                                                    else {
                                                            prim $= "J";
                                                            sec  $= "K";
                                                    }
                                            }
                                            cur += 2;
                                            break;
                                    }

                                    if (mid(in, cur +1, 1) == "G") cur += 2;
                                    else cur++;

                                    prim $= "K";
                                    sec  $= "K";
                                    break;

                            case "H":
                                    // only keep if first & before vowel or btw. 2 vowels
                                    if (((cur == 0) || is_vowel(in, cur - 1)) && is_vowel(in, cur + 1))
                                    {
                                            prim $= "H";
                                            sec  $= "H";
                                            cur += 2;
                                    }
                                    else cur++;
                                    break;

                            case "J":
                                    // obvious spanish, 'jose', 'san jacinto'
                                    if ((mid(in, cur, 4) == "JOSE")
                                            || (mid(in, 0, 4) == "SAN "))
                                    {
                                            if (((cur == 0) && (mid(in, cur + 4, 1) == " "))
                                                    || (mid(in, 0, 4) == "SAN "))
                                            {
                                                    prim $= "H";
                                                    sec  $= "H";
                                            }
                                            else {
                                                    prim $= "J";
                                                    sec  $= "H";
                                            }
                                            cur++;
                                            break;
                                    }

                                    if ((cur == 0) && (mid(in, cur, 4) != "JOSE"))
                                    {
                                            prim $= "J";  // Yankelovich/Jankelowicz
                                            sec  $= "A";
                                    }
                                    else {
                                            // spanish pron. of .e.g. 'bajador'
                                            if (is_vowel(in, cur - 1)
                                                    && !Slavo_Germanic(in)
                                                    && ((mid(in, cur + 1, 1) == "A")
                                                    || (mid(in, cur + 1, 1) == "O")))
                                            {
                                                    prim $= "J";
                                                    sec  $= "H";
                                            }
                                            else {
                                                    if (cur == last)
                                                    {
                                                            prim $= "J";
                                                            sec  $= "";
                                                    }
                                                    else {
                                                            if ((InStr("LTKSNMBZ", mid(in, cur + 1, 1)) == -1)
                                                                    && (InStr("SKL", mid(in, cur - 1, 1)) == -1) )
                                                            {
                                                                    prim $= "J";
                                                                    sec  $= "J";
                                                            }
                                                    }
                                            }
                                    }

                                    if (mid(in, cur + 1, 1) == "J") // it could happen
                                            cur += 2;
                                    else
                                            cur++;
                                    break;

                            case "K":
                                    if (mid(in, cur + 1, 1) == "K") cur += 2;
                                    else cur++;
                                    prim $= "K";
                                    sec  $= "K";
                                    break;

                            case "L":
                                    if (mid(in, cur + 1, 1) == "L")
                                    {
                                            // spanish e.g. 'cabrillo', 'gallegos'
                                            if (((cur == (slen - 3))
                                                    && (smid(in, cur-1, 4, tmp) == "ILLO"
                                                            || tmp == "ILLA"
                                                            || tmp == "ALLE"
                                                    )
                                                    || (
                                                            ((smid(in, last-1, 2, tmp) == "AS"
                                                                    || tmp == "OS")
                                                                    || (InStr("AO", mid(in, last, 1)) > -1)
                                                            )
                                                            && (mid(in, cur - 1, 4) == "ALLE")
                                                            )
                                                    ))
                                            {
                                                    prim $= "L";
                                                    sec  $= "";
                                                    cur += 2;
                                                    break;
                                            }
                                            cur += 2;
                                    } else cur++;
                                    prim $= "L";
                                    sec  $= "L";
                                    break;

                            case "M":
                                    if (((mid(in, cur-1, 3) == "UMB")
                                            && (((cur + 1) == last)
                                            || (mid(in, cur+2, 2) == "ER")))
                                            // 'dumb', 'thumb'
                                            || (mid(in, cur + 1, 1) == "M"))
                                    {
                                            cur += 2;
                                    }
                                    else {
                                            cur++;
                                    }
                                    prim $= "M";
                                    sec  $= "M";
                                    break;

                            case "N":
                                    if (mid(in, cur + 1, 1) == "N") cur += 2;
                                    else cur++;
                                    prim $= "N";
                                    sec  $= "N";
                                    break;

                            case "Ñ":
                                    cur++;
                                    prim $= "N";
                                    sec  $= "N";
                                    break;

                            case "P":
                                    if (mid(in, cur + 1, 1) == "H")
                                    {
                                            cur += 2;
                                            prim $= "F";
                                            sec  $= "F";
                                            break;
                                    }

                                    // also account for "campbell" and "raspberry"
                                    if (InStr("PB", Mid(in, cur + 1, 1)) > -1)
                                            cur += 2;
                                    else
                                            cur++;
                                    prim $= "P";
                                    sec  $= "P";
                                    break;

                            case "Q":
                                    if (mid(in, cur + 1, 1) == "Q") cur += 2;
                                    else cur++;
                                    prim $= "K";
                                    sec  $= "K";
                                    break;

                            case "R":
                                    // french e.g. 'rogier', but exclude 'hochmeier'
                                    if ((cur == last)
                                            && !Slavo_Germanic(in)
                                            && (mid(in, cur - 2, 2) == "IE")
                                            && !(smid(in, cur-4, 2, tmp) == "ME"
                                                    || tmp == "MA"
                                            ))
                                    {
                                            prim $= "";
                                            sec  $= "R";
                                    }
                                    else {
                                            prim $= "R";
                                            sec  $= "R";
                                    }
                                    if (mid(in, cur + 1, 1) == "R") cur += 2;
                                    else cur++;
                                    break;

                            case "S":
                                    // special cases 'island', 'isle', 'carlisle', 'carlysle'
                                    if ((smid(in, cur - 1, 3, tmp) == "ISL")
                                            || (tmp == "YSL"))
                                    {
                                            cur++;
                                            break;
                                    }

                                    // special case 'sugar-'
                                    if ((cur == 0) && (mid(in, cur, 5) == "SUGAR"))
                                    {
                                            prim $= "X";
                                            sec  $= "S";
                                            cur++;
                                            break;
                                    }

                                    if (mid(in, cur, 2) == "SH")
                                    {
                                            // germanic
                                            if (smid(in, cur + 1, 4, tmp) == "HEIM"
                                                    || tmp == "HOEK"
                                                    || tmp == "HOLM"
                                                    || tmp == "HOLZ")
                                            {
                                                    prim $= "S";
                                                    sec  $= "S";
                                            }
                                            else {
                                                    prim $= "X";
                                                    sec  $= "X";
                                            }
                                            cur += 2;
                                            break;
                                    }

                                    // italian & armenian
                                    if (smid(in, cur, 3, tmp) == "SIO"
                                            || tmp == "SIA"
                                            || mid(in, cur, 4) == "SIAN")
                                    {
                                            if (!Slavo_Germanic(in))
                                            {
                                                    prim $= "S";
                                                    sec  $= "X";
                                            }
                                            else {
                                                    prim $= "S";
                                                    sec  $= "S";
                                            }
                                            cur += 3;
                                            break;
                                    }

                                    // german & anglicisations, e.g. 'smith' match 'schmidt', 'snider' match 'schneider'
                                    // also, -sz- in slavic language altho in hungarian it is pronounced 's'
                                    if ((
                                                    (cur == 0)
                                                    && (InStr("MNLW", mid(in, cur + 1, 1)) > -1)
                                            )
                                            || mid(in, cur + 1, 1) == "Z")
                                    {
                                            prim $= "S";
                                            sec  $= "X";
                                            if (mid(in, cur + 1, 1) == "Z")      cur += 2;
                                            else cur++;
                                            break;
                                    }

                                    if (mid(in, cur, 2) == "SC")
                                    {
                                            // Schlesinger's rule
                                            if (mid(in, cur + 2, 1) == "H")
                                            {
                                                    // dutch origin, e.g. 'school', 'schooner'
                                                    if (smid(in, cur + 3, 2, tmp) == "OO"
                                                            || tmp == "ER"
                                                            || tmp == "EN"
                                                            || tmp == "UY"
                                                            || tmp == "ED"
                                                            || tmp == "EM")
                                                    {
                                                            // 'schermerhorn', 'schenker'
                                                            if (smid(in, cur + 3, 2, tmp) == "ER"
                                                                    || tmp == "EN")
                                                            {
                                                                    prim $= "X";
                                                                    sec  $= "SK";
                                                            } else {
                                                                    prim $= "SK";
                                                                    sec  $= "SK";
                                                            }
                                                            cur += 3;
                                                            break;
                                                    } else {
                                                            if ((cur == 0)
                                                                    && !is_vowel(in, 3)
                                                                    && (mid(in, cur + 3, 1) != "W"))
                                                            {
                                                                    prim $= "X";
                                                                    sec  $= "S";
                                                            } else {
                                                                    prim $= "X";
                                                                    sec  $= "X";
                                                            }
                                                            cur += 3;
                                                            break;
                                                    }

                                                    if (InStr("IEY", mid(in, cur + 2, 1)) > -1)
                                                    {
                                                            prim $= "S";
                                                            sec  $= "S";
                                                            cur += 3;
                                                            break;
                                                    }
                                            }

                                            // else
                                            prim $= "SK";
                                            sec  $= "SK";
                                            cur += 3;
                                            break;
                                    }

                                    // french e.g. 'resnais', 'artois'
                                    if ((cur == last)
                                            && (
                                                    smid(in, cur-2, 2, tmp) == "AI"
                                                    || tmp == "OI"
                                            ))
                                    {
                                            prim $= "";
                                            sec  $= "S";
                                    } else {
                                            prim $= "S";
                                            sec  $= "S";
                                    }

                                    if (InStr("SZ", mid(in, cur + 1, 1)) > -1)
                                            cur += 2;
                                    else
                                            cur++;
                                    break;

                            case "T":
                                    if (mid(in, cur, 4) == "TION")
                                    {
                                            prim $= "X";
                                            sec  $= "X";
                                            cur += 3;
                                            break;
                                    }

                                    if (smid(in, cur, 3, tmp) == "TIA"
                                            || tmp == "TCH")
                                    {
                                            prim $= "X";
                                            sec  $= "X";
                                            cur += 3;
                                            break;
                                    }

                                    if ((mid(in, cur, 2) == "TH")
                                            || (mid(in, cur, 3) == "TTH"))
                                    {
                                            // special case 'thomas', 'thames' or germanic
                                            if (smid(in, cur + 2, 2, tmp) == "OM"
                                                    || tmp == "AM"
                                                    || smid(in, 0, 4, tmp) == "VAN"
                                                    || tmp == "VON"
                                                    || mid(in, 0, 3) == "SCH")
                                            {
                                                    prim $= "T";
                                                    sec  $= "T";
                                            } else {
                                                    prim $= "O";
                                                    sec  $= "T";
                                            }
                                            cur += 2;
                                            break;
                                    }

                                    if (InStr("TD", mid(in, cur + 1, 1)) > -1)
                                            cur += 2;
                                    else
                                            cur++;
                                    prim $= "T";
                                    sec  $= "T";
                                    break;

                            case "V":
                                    if (mid(in, cur + 1, 1) == "V")
                                            cur += 2;
                                    else
                                            cur++;
                                    prim $= "F";
                                    sec  $= "F";
                                    break;

                            case "W":
                                    // can also be in middle of word
                                    if (mid(in, cur, 2) == "WR") {
                                            prim $= "R";
                                            sec  $= "R";
                                            cur += 2;
                                            break;
                                    }

                                    if ((cur == 0)
                                            && (is_vowel(in, cur + 1)
                                                    || mid(in, cur, 2) == "WH"))
                                    {
                                            // Wasserman should match Vasserman
                                            if (is_vowel(in, cur + 1))
                                            {
                                                    prim $= "A";
                                                    sec  $= "F";
                                            }
                                            else {
                                                    // need Uomo to match Womo
                                                    prim $= "A";
                                                    sec  $= "A";
                                            }
                                    }

                                    // Arnow should match Arnoff
                                    if (((cur == last)
                                                    && is_vowel(in, cur - 1))
                                            || smid(in, cur - 1, 5, tmp) =="EWSKI"
                                            || tmp == "EWSKY"
                                            || tmp == "OWSKI"
                                            || tmp == "OWSKY"
                                            || mid(in, 0, 3) == "SCH")
                                    {
                                            prim $= "";
                                            sec  $= "F";
                                            cur++;
                                            break;
                                    }

                                    // polish e.g. 'filipowicz'
                                    if (smid(in, cur, 4, tmp) == "WICZ"
                                            || tmp == "WITZ")
                                    {
                                            prim $= "TS";
                                            sec  $= "FX";
                                            cur += 4;
                                            break;
                                    }

                                    // else skip it
                                    cur++;
                                    break;

                            case "X":
                                    // french e.g. breaux
                                    if (!((cur == last)
                                            && (smid(in, cur - 3, 3, tmp) == "IAU"
                                                    || tmp == "EAU"
                                                    || smid(in, cur - 2, 2, tmp) == "AU"
                                                    || tmp == "OU")))
                                    {
                                            prim $= "KS";
                                            sec  $= "KS";
                                    }

                                    if (InStr("CX", mid(in, cur + 1, 1)) > -1)
                                            cur += 2;
                                    else
                                            cur++;
                                    break;

                            case "Z":
                                    // chinese pinyin e.g. 'zhao'
                                    if (mid(in, cur + 1, 1) == "H")
                                    {
                                            prim $= "J";
                                            sec  $= "J";
                                            cur += 2;
                                            break;
                                    }
                                    else
                                            if (smid(in, cur + 1, 2, tmp) == "ZO"
                                                    || tmp == "ZI"
                                                    || tmp == "ZA"
                                                    || (Slavo_Germanic(in)
                                                    && ((cur > 0) && mid(in, cur - 1, 1) != "T")))
                                            {
                                            prim $= "S";
                                            sec  $= "TS";
                                    } else {
                                            prim $= "S";
                                            sec  $= "S";
                                    }

                                    if (mid(in, cur + 1, 1) == "Z")
                                            cur += 2;
                                    else
                                            cur++;
                                    break;

                            default:
                                    cur++;
                    }
            }

            res[0] = Left(prim, mlen);
            res[1] = Left(sec, mlen);
            return res;
    }

## Helper functions

    /**
            Same as mid, except that is has a 4th param that will also get the result. <br />
            Use this for caching the result.
    */
    static final function string smid(coerce string in, int off, int len, out string s)
    {
            s = mid(in, off, len);
            return s;
    }

    /**
            returns true if the character at pos is a vowel.
    */
    static final function bool is_vowel(coerce string in, int pos)
    {
            return (InStr("AEIOUY", mid(in, pos, 1)) > -1);
    }

    /**
            helper function for the metaphone algorithm to determain if this word is
            "slave germanic"
    */
    static final function bool Slavo_Germanic(coerce string in)
    {
            return (InStr(in, "W") > -1)
                    || (InStr(in, "K") > -1)
                    || (InStr(in, "CZ") > -1)
                    || (InStr(in, "WITZ") > -1);
    }

## Copyright

       Copyright 2004, Michiel Hendriks <elmuerte@drunksnipers.com>
       All rights reserved.

       This UnrealScript translation is based heavily on the PHP
       implementation by Stephen Woodbridge <woodbri@swoodbridge.com>,
       which in turn is based on the C implementation
       by Maurice Aubrey <maurice@hevanet.com>, which in turn
       is based heavily on the C++ implementation by
       Lawrence Philips and incorporates several bug fixes courtesy
       of Kevin Atkinson <kevina@users.sourceforge.net>.

       This module is free software; you may redistribute it and/or
       modify it under the same terms as Perl itself.

The Perl Artistic License.

Note that that page currently appears to be blank, the Perl Artistic License is almost similar to the Artistic License

Wormbo: Erm... Perl?

El Muerte: Yeah go figure, just pasting a long the license notice. The implementation of Maurice Aubrey has been released under that license, and so is the PHP implementation, thus this implementation should also be released under the same license. The license isn't very restrictive, it allows you to do even more than the LesserOpenUnrealModLicense would do.

## Related Topics

- SoundEx
- More about metaphone – and implementations in other languages

Category: Legacy Algorithm

##### Views

- Legacy
- Discussion
- Current revision

##### Search