NYSIIS: Difference between revisions

80,734 bytes added ,  4 months ago
m
m (→‎{{header|Java}}: remove redundant letter)
m (→‎{{header|Wren}}: Minor tidy)
 
(33 intermediate revisions by 14 users not shown)
Line 1:
{{draft task|text processing}}
{{wikipedia}}
The [[wp:New York State Identification and Intelligence System|New York State Identification and Intelligence System phonetic code]], commonly known as NYSIIS, is a phonetic algorithm for creating indices for words based on their pronunciation. The goal is for homophones to be encoded to the same representation so that they can be matched despite minor differences in spelling.
 
The task here is to implement the original NYSIIS algorithm, shown in Wikipedia, rather than any other subsequent modification. Also, before the algorithm is applied the input string should be converted to upper case with all white space removed.
 
The [[wp:New York State Identification and Intelligence System|New York State Identification and Intelligence System phonetic code]], commonly known as NYSIIS, is a phonetic algorithm for creating indices for words based on their pronunciation.
An optional step is to handle multiple names, including double-barrelled names or double surnames (e.g. 'Hoyle-Johnson' or 'Vaughan Williams') and unnecessary suffixes/honours that are not required for indexing purposes (e.g. 'Jnr', 'Sr', 'III', etc) - a small selection will suffice. The original implementation is also restricted to six characters, but this is not a requirement.
 
The goal is for homophones to be encoded to the same representation so that they can be matched despite minor differences in spelling.
 
 
;Task:
Implement the original NYSIIS algorithm, shown in Wikipedia, rather than any other subsequent modification.
 
Also, before the algorithm is applied the input string should be converted to upper case with all white space removed.
 
An optional step is to handle multiple names, including double-barrelled names or double surnames (e.g. 'Hoyle-Johnson' or 'Vaughan Williams') and unnecessary suffixes/honours that are not required for indexing purposes (e.g. 'Jnr', 'Sr', 'III', etc) - a small selection will suffice.
 
The original implementation is also restricted to six characters, but this is not a requirement.
 
 
;See also
* [[Soundex]]
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">V _vowels = ‘AEIOU’
 
F replace_at(String text; position, fromlist, tolist)
L(f, t) zip(fromlist, tolist)
I text[position .+ f.len] == f
R text[0 .< position]‘’t‘’text[position + f.len ..]
R text
 
F replace_end(String text; fromlist, tolist)
L(f, t) zip(fromlist, tolist)
I text.ends_with(f)
R text[0 .< (len)-f.len]‘’t
R text
 
F nysiis(String =name)
name = name.replace(re:‘\W’, ‘’).uppercase()
name = replace_at(name, 0, [‘MAC’, ‘KN’, ‘K’, ‘PH’, ‘PF’, ‘SCH’],
[‘MCC’, ‘N’, ‘C’, ‘FF’, ‘FF’, ‘SSS’])
name = replace_end(name, [‘EE’, ‘IE’, ‘DT’, ‘RT’, ‘RD’, ‘NT’, ‘ND’],
[‘Y’, ‘Y’, ‘D’, ‘D’, ‘D’, ‘D’, ‘D’])
V key = String(name[0])
V key1 = ‘’
V i = 1
L i < name.len
V (n_1, n) = (name[i - 1], name[i])
V n1_ = I i + 1 < name.len {name[i + 1]} E ‘’
name = replace_at(name, i, [‘EV’] [+] Array(:_vowels).map(String), [‘AF’] [+] [String(‘A’)] * 5)
name = replace_at(name, i, [String(‘Q’), ‘Z’, ‘M’], [String(‘G’), ‘S’, ‘N’])
name = replace_at(name, i, [‘KN’, ‘K’], [String(‘N’), ‘C’])
name = replace_at(name, i, [‘SCH’, ‘PH’], [‘SSS’, ‘FF’])
I n == ‘H’ & (n_1 !C :_vowels | n1_ !C :_vowels)
name = name[0 .< i]‘’n_1‘’name[i + 1 ..]
I n == ‘W’ & n_1 C :_vowels
name = name[0 .< i]‘A’name[i + 1 ..]
I key != ‘’ & key.last != name[i]
key ‘’= name[i]
i++
key = replace_end(key, [‘S’, ‘AY’, ‘A’], [‘’, ‘Y’, ‘’])
R key1‘’key
 
V names = [‘Bishop’, ‘Carlson’, ‘Carr’, ‘Chapman’, ‘Franklin’,
‘Greene’, ‘Harper’, ‘Jacobs’, ‘Larson’, ‘Lawrence’,
‘Lawson’, ‘Louis, XVI’, ‘Lynch’, ‘Mackenzie’, ‘Matthews’,
‘McCormack’, ‘McDaniel’, ‘McDonald’, ‘Mclaughlin’, ‘Morrison’,
‘O'Banion’, ‘O'Brien’, ‘Richards’, ‘Silva’, ‘Watkins’,
‘Wheeler’, ‘Willis’, ‘brown, sr’, ‘browne, III’, ‘browne, IV’,
‘knight’, ‘mitchell’, ‘o'daniel’]
L(name) names
print(‘#15: #.’.format(name, nysiis(name)))</syntaxhighlight>
 
{{out}}
<pre>
Bishop: BASAP
Carlson: CARLSAN
Carr: CAR
Chapman: CAPNAN
Franklin: FRANCLAN
Greene: GRAN
Harper: HARPAR
Jacobs: JACAB
Larson: LARSAN
Lawrence: LARANC
Lawson: LASAN
Louis, XVI: LASXV
Lynch: LYNC
Mackenzie: MCANSY
Matthews: MATA
McCormack: MCARNAC
McDaniel: MCDANAL
McDonald: MCDANALD
Mclaughlin: MCLAGLAN
Morrison: MARASAN
O'Banion: OBANAN
O'Brien: OBRAN
Richards: RACARD
Silva: SALV
Watkins: WATCAN
Wheeler: WALAR
Willis: WALA
brown, sr: BRANSR
browne, III: BRAN
browne, IV: BRANAV
knight: NAGT
mitchell: MATCAL
o'daniel: ODANAL
</pre>
 
=={{header|C++}}==
Implementation based on Wikipedia description of the algorithm.
 
<syntaxhighlight lang="c">
#include <iostream> // required for debug code in main() only
#include <iomanip> // required for debug code in main() only
#include <string>
 
std::string NYSIIS( std::string const& str )
{
std::string s, out;
s.reserve( str.length() );
for( auto const c : str )
{
if( c >= 'a' && c <= 'z' )
s += c - ('a' - 'A');
else if( c >= 'A' && c <= 'Z' )
s += c;
}
 
auto replace = []( char const * const from, char const* to, char* const dst ) -> bool
{
auto const n = strlen( from );
if( strncmp( from, dst, n ) == 0 )
{
strncpy( dst, to, n );
return true;
}
return false;
};
 
auto multiReplace = []( char const* const* from, char const* to, char* const dst ) -> bool
{
auto const n = strlen( *from );
for( ; *from; ++from )
if( strncmp( *from, dst, n ) == 0 )
{
memcpy( dst, to, n );
return true;
}
return false;
};
 
auto isVowel = []( char const c ) -> bool
{
return c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U';
};
 
size_t n = s.length();
replace( "MAC", "MCC", &s[0] );
replace( "KN", "NN", &s[0] );
replace( "K", "C", &s[0] );
char const* const prefix[] = { "PH", "PF", 0 };
multiReplace( prefix, "FF", &s[0] );
replace( "SCH", "SSS", &s[0] );
 
char const* const suffix1[] = { "EE", "IE", 0 };
char const* const suffix2[] = { "DT", "RT", "RD", "NT", "ND", 0 };
if( multiReplace( suffix1, "Y", &s[n - 2] ) || multiReplace( suffix2, "D", &s[n - 2] ))
{
s.pop_back();
--n;
}
 
out += s[0];
 
char* vowels[] = { "A", "E", "I", "O", "U", 0 };
for( unsigned i = 1; i < n; ++i )
{
char* const c = &s[i];
if( !replace( "EV", "AV", c ) )
multiReplace( vowels, "A", c );
replace( "Q", "G", c );
replace( "Z", "S", c );
replace( "M", "N", c );
if( !replace( "KN", "NN", c ))
replace( "K", "C", c );
replace( "SCH", "SSS", c );
replace( "PH", "FF", c );
if( *c == 'H' && (!isVowel( s[i - 1] ) || i + 1 >= n || !isVowel( s[i + 1] )))
*c = s[i - 1];
if( *c == 'W' && isVowel( s[i - 1] ))
*c = 'A';
if( out.back() != *c )
out += *c;
}
 
if( out.back() == 'S' || out.back() == 'A' )
out.pop_back();
n = out.length() - 2;
if( out[n] == 'A' && out[n + 1] == 'Y' )
out = out.substr( 0, n ) + "Y";
 
return out;
}
 
int main()
{
static char const * const names[][2] = {
{ "Bishop", "BASAP" },
{ "Carlson", "CARLSAN" },
{ "Carr", "CAR" },
{ "Chapman", "CAPNAN" },
{ "Franklin", "FRANCLAN" },
{ "Greene", "GRAN" },
{ "Harper", "HARPAR" },
{ "Jacobs", "JACAB" },
{ "Larson", "LARSAN" },
{ "Lawrence", "LARANC" },
{ "Lawson", "LASAN" },
{ "Louis, XVI", "LASXV" },
{ "Lynch", "LYNC" },
{ "Mackenzie", "MCANSY" },
{ "Matthews", "MATA" },
{ "McCormack", "MCARNAC" },
{ "McDaniel", "MCDANAL" },
{ "McDonald", "MCDANALD" },
{ "Mclaughlin", "MCLAGLAN" },
{ "Morrison", "MARASAN" },
{ "O'Banion", "OBANAN" },
{ "O'Brien", "OBRAN" },
{ "Richards", "RACARD" },
{ "Silva", "SALV" },
{ "Watkins", "WATCAN" },
{ "Wheeler", "WALAR" },
{ "Willis", "WALA" },
{ "brown, sr", "BRANSR" },
{ "browne, III", "BRAN" },
{ "browne, IV", "BRANAV" },
{ "knight", "NAGT" },
{ "mitchell", "MATCAL" },
{ "o'daniel", "ODANAL" } };
 
for( auto const& name : names )
{
auto const code = NYSIIS( name[0] );
std::cout << std::left << std::setw( 16 ) << name[0] << std::setw( 8 ) << code;
if( code == std::string( name[1] ))
std::cout << " ok";
else
std::cout << " ERROR: " << name[1] << " expected";
std::cout << std::endl;
}
 
return 0;
}
 
</syntaxhighlight>
{{out|Example output}}
<pre>
Bishop BASAP ok
Carlson CARLSAN ok
Carr CAR ok
Chapman CAPNAN ok
Franklin FRANCLAN ok
Greene GRAN ok
Harper HARPAR ok
Jacobs JACAB ok
Larson LARSAN ok
Lawrence LARANC ok
Lawson LASAN ok
Louis, XVI LASXV ok
Lynch LYNC ok
Mackenzie MCANSY ok
Matthews MATA ok
McCormack MCARNAC ok
McDaniel MCDANAL ok
McDonald MCDANALD ok
Mclaughlin MCLAGLAN ok
Morrison MARASAN ok
O'Banion OBANAN ok
O'Brien OBRAN ok
Richards RACARD ok
Silva SALV ok
Watkins WATCAN ok
Wheeler WALAR ok
Willis WALA ok
brown, sr BRANSR ok
browne, III BRAN ok
browne, IV BRANAV ok
knight NAGT ok
mitchell MATCAL ok
o'daniel ODANAL ok
</pre>
 
=={{header|Caché ObjectScript}}==
Refactored code based on other examples to reduce footprint.
 
<langsyntaxhighlight lang="cos">
Class Utils.Phonetic [ Abstract ]
{
Line 126 ⟶ 413:
 
}
</syntaxhighlight>
</lang>
{{out|Examples}}
<pre>
Line 172 ⟶ 459:
=={{header|D}}==
{{trans|Python}}
<langsyntaxhighlight lang="d">import std.stdio, std.regex, std.algorithm, std.range, std.string;
 
string replaceAt(in string text, in uint pos, in string[] fromList,
in string[] toList) pure /*nothrow*/ @safe {
foreach (const f, const t; zip(fromList, toList))
if (text[pos .. $].startsWith(f))
Line 183 ⟶ 470:
 
string replaceEnd(in string text, in string[] fromList,
in string[] toList) pure /*nothrow*/ @safe {
foreach (const f, const t; zip(fromList, toList))
if (text.endsWith(f))
Line 190 ⟶ 477:
}
 
string nysiis(string name) /*pure nothrow*/ @safe {
enum vowels = "AEIOU";
name = name.replaceAll(r"\W".regex, "").toUpper;
Line 220 ⟶ 507:
}
 
void main() @safe {
immutable names = ["Bishop", "Carlson", "Carr", "Chapman",
"Franklin", "Greene", "Harper", "Jacobs", "Larson", "Lawrence",
Line 231 ⟶ 518:
foreach (immutable name; names)
writefln("%11s: %s", name, name.nysiis);
}</langsyntaxhighlight>
{{out}}
<pre> Bishop: BASAP
Line 266 ⟶ 553:
mitchell: MATCAL
o'daniel: ODANAL</pre>
 
=={{header|Go}}==
{{trans|Kotlin}}
<syntaxhighlight lang="go">package main
 
import (
"fmt"
"strings"
)
 
type pair struct{ first, second string }
 
var (
fStrs = []pair{{"MAC", "MCC"}, {"KN", "N"}, {"K", "C"}, {"PH", "FF"},
{"PF", "FF"}, {"SCH", "SSS"}}
lStrs = []pair{{"EE", "Y"}, {"IE", "Y"}, {"DT", "D"}, {"RT", "D"},
{"RD", "D"}, {"NT", "D"}, {"ND", "D"}}
mStrs = []pair{{"EV", "AF"}, {"KN", "N"}, {"SCH", "SSS"}, {"PH", "FF"}}
eStrs = []string{"JR", "JNR", "SR", "SNR"}
)
 
func isVowel(b byte) bool {
return strings.ContainsRune("AEIOU", rune(b))
}
 
func isRoman(s string) bool {
if s == "" {
return false
}
for _, r := range s {
if !strings.ContainsRune("IVX", r) {
return false
}
}
return true
}
 
func nysiis(word string) string {
if word == "" {
return ""
}
w := strings.ToUpper(word)
ww := strings.FieldsFunc(w, func(r rune) bool {
return r == ' ' || r == ','
})
if len(ww) > 1 {
last := ww[len(ww)-1]
if isRoman(last) {
w = w[:len(w)-len(last)]
}
}
for _, c := range " ,'-" {
w = strings.Replace(w, string(c), "", -1)
}
for _, eStr := range eStrs {
if strings.HasSuffix(w, eStr) {
w = w[:len(w)-len(eStr)]
}
}
for _, fStr := range fStrs {
if strings.HasPrefix(w, fStr.first) {
w = strings.Replace(w, fStr.first, fStr.second, 1)
}
}
for _, lStr := range lStrs {
if strings.HasSuffix(w, lStr.first) {
w = w[:len(w)-2] + lStr.second
}
}
initial := w[0]
var key strings.Builder
key.WriteByte(initial)
w = w[1:]
for _, mStr := range mStrs {
w = strings.Replace(w, mStr.first, mStr.second, -1)
}
sb := []byte{initial}
sb = append(sb, w...)
le := len(sb)
for i := 1; i < le; i++ {
switch sb[i] {
case 'E', 'I', 'O', 'U':
sb[i] = 'A'
case 'Q':
sb[i] = 'G'
case 'Z':
sb[i] = 'S'
case 'M':
sb[i] = 'N'
case 'K':
sb[i] = 'C'
case 'H':
if !isVowel(sb[i-1]) || (i < le-1 && !isVowel(sb[i+1])) {
sb[i] = sb[i-1]
}
case 'W':
if isVowel(sb[i-1]) {
sb[i] = 'A'
}
}
}
if sb[le-1] == 'S' {
sb = sb[:le-1]
le--
}
if le > 1 && string(sb[le-2:]) == "AY" {
sb = sb[:le-2]
sb = append(sb, 'Y')
le--
}
if le > 0 && sb[le-1] == 'A' {
sb = sb[:le-1]
le--
}
prev := initial
for j := 1; j < le; j++ {
c := sb[j]
if prev != c {
key.WriteByte(c)
prev = c
}
}
return key.String()
}
 
func main() {
names := []string{
"Bishop", "Carlson", "Carr", "Chapman",
"Franklin", "Greene", "Harper", "Jacobs", "Larson", "Lawrence",
"Lawson", "Louis, XVI", "Lynch", "Mackenzie", "Matthews", "May jnr",
"McCormack", "McDaniel", "McDonald", "Mclaughlin", "Morrison",
"O'Banion", "O'Brien", "Richards", "Silva", "Watkins", "Xi",
"Wheeler", "Willis", "brown, sr", "browne, III", "browne, IV",
"knight", "mitchell", "o'daniel", "bevan", "evans", "D'Souza",
"Hoyle-Johnson", "Vaughan Williams", "de Sousa", "de la Mare II",
}
for _, name := range names {
name2 := nysiis(name)
if len(name2) > 6 {
name2 = fmt.Sprintf("%s(%s)", name2[:6], name2[6:])
}
fmt.Printf("%-16s : %s\n", name, name2)
}
}</syntaxhighlight>
 
{{out}}
<pre>
Bishop : BASAP
Carlson : CARLSA(N)
Carr : CAR
Chapman : CAPNAN
Franklin : FRANCL(AN)
Greene : GRAN
Harper : HARPAR
Jacobs : JACAB
Larson : LARSAN
Lawrence : LARANC
Lawson : LASAN
Louis, XVI : LA
Lynch : LYNC
Mackenzie : MCANSY
Matthews : MATA
May jnr : MY
McCormack : MCARNA(C)
McDaniel : MCDANA(L)
McDonald : MCDANA(LD)
Mclaughlin : MCLAGL(AN)
Morrison : MARASA(N)
O'Banion : OBANAN
O'Brien : OBRAN
Richards : RACARD
Silva : SALV
Watkins : WATCAN
Xi : X
Wheeler : WALAR
Willis : WAL
brown, sr : BRAN
browne, III : BRAN
browne, IV : BRAN
knight : NAGT
mitchell : MATCAL
o'daniel : ODANAL
bevan : BAFAN
evans : EVAN
D'Souza : DSAS
Hoyle-Johnson : HAYLAJ(ANSAN)
Vaughan Williams : VAGANW(ALAN)
de Sousa : DASAS
de la Mare II : DALANA(R)
</pre>
 
=={{header|Java}}==
{{works with|Java|8}}
<langsyntaxhighlight lang="java">import static java.util.Arrays.*;
import static java.lang.System.out;
 
Line 283 ⟶ 760:
 
public static void main(String[] args) {
stream(args).parallel().map(NYSIIS::n -> transcode(n)).forEach(out::println);
}
 
Line 353 ⟶ 830:
if (sb.lastIndexOf("AY") == lastPos - 1)
sb.delete(lastPos - 1, lastPos + 1).append("Y");
 
else if (sb.lastIndexOf("AS") == lastPos - 1)
sb.setLength(lastPos - 1);
 
else if (sb.charAt(lastPos) == 'S')
Line 383 ⟶ 857:
return Vowels.indexOf(c) != -1;
}
}</langsyntaxhighlight>
 
<pre>MatthewsCarr -> MATCAR
Carr -> CAR
Lawson -> LASAN
ChapmanLouisXVI -> CAPNANLASXV
Greene -> GRAN
Willis -> WALA
Mackenzie -> MCANSY
brownsr -> BRANSR
browneIV -> BRANAV
O'Brien -> OBRAN
LouisXVILynch -> LASXVLYNC
Wheeler -> WALAR
Carlson -> CARLSA[N]
Lawrence -> LARANC
GreeneLarson -> GRANLARSAN
McCormack -> MCARNA[C]
Jacobs -> JACAB
Willis -> WAL
browneIV -> BRANAV
Harper -> HARPAR
browneIII -> BRAN
Mclaughlin -> MCLAGL[AN]
mitchell -> MATCAL
Morrison -> MARASA[N]
o'daniel -> ODANAL
Franklin -> FRANCL[AN]
McDonald -> MCDANA[LD]
knightO'Banion -> NAGTOBANAN
McDaniel -> MCDANA[L]
Larson -> LARSAN
Silva -> SALV
Wheelermitchell -> WALARMATCAL
Richards -> RACARD
Carlson -> CARLSA[N]
browneIII -> BRAN
Matthews -> MATA
knight -> NAGT
Franklin -> FRANCL[AN]
Chapman -> CAPNAN
Bishop -> BASAP
Oo'Baniondaniel -> OBANANODANAL
Watkins -> WATCAN</pre>
McCormack -> MCARNA[C]
Watkins -> WATCAN
Lynch -> LYNC
Mackenzie -> MCANSY
brownsr -> BRANSR</pre>
 
=={{header|Perl 6Julia}}==
{{works with|Julia|0.6}}
This implementation removes common name suffixes similar to the reference implementation, even though it is not specified in the task description or on the linked [[wp:New York State Identification and Intelligence System|NYSIIS]] page. This algorithm isn't too friendly to certain French kings. :)
{{trans|Python}}
 
<syntaxhighlight lang="julia">function replaceat(text::AbstractString, position::Int, fromlist, tolist)
<lang perl6>sub no_suffix ($name) {
for (f, t) in zip(fromlist, tolist)
$name.uc.subst: /\h (<[JS]>R) | (<[IVX]>+) $/, '';
if startswith(text[position:end], f)
}
return text[1:position-1] * t * text[position+length(f):end]
end
end
return text
end
 
function replaceend(text::AbstractString, fromlist, tolist)
sub nysiis ($name is copy) {
for (f, t) in zip(fromlist, tolist)
given $name .= uc {
s:g/<-[A..Z]>//;if endswith(text, f)
return text[1:end-length(f)] * t
s/^MAC/MCC/;
s/^P<[FH]>/FF/;end
end
s/^SCH/SSS/;
return s/^KN/N/;text
end
s/<[IE]>E$ /Y/;
s/<[DRN]>T$ /D/;
s/<[RN]>D$ /D/;
s:c(1):g/EV/AF/;
s:c(1):g/<[AEIOU]>+/A/;
s:c(1):g/Q/G/;
s:c(1):g/Z/S/;
s:c(1):g/M/N/;
s:c(1):g/KN/N/;
s:c(1):g/K/C/;
s:c(1):g/SCH/S/;
s:c(1):g/PF/F/;
s:c(1):g/K/C/;
s:c(1):g/H(<-[AEIOU]>)/$0/;
s:g/(<-[AEIOU]>)H/$0/;
s:g/(<-[AEIOU]>)W/$0/;
s/ AY$ /Y/;
s/ S$ //;
s/ A$ //;
s:g/ (.)$0+ /$0/;
}
}
 
function nysiis(name::AbstractString)
vowels = ["A", "E", "I", "O", "U"]
 
name = uppercase(filter(isalpha, name))
for «
name = replaceat(name, 1, ["MAC", "KN", "K", "PH", "PF", "SCH"],
knight mitchell "o'daniel" "brown sr" "browne III"
"browne IV" "O'Banion" Mclaughlin McCormack Chapman ["MCC", "N", "C", "FF", "FF", "SSS"])
name = replaceend(name, ["EE", "IE", "DT", "RT", "RD", "NT", "ND"],
Silva McDonald Lawson Jacobs Greene
"O'Brien" Morrison Larson Willis ["Y", "Y", "D", Mackenzie"D", "D", "D", "D"])
key, key1 = name[1:1], ""
Carr Lawrence Matthews Richards Bishop
for i in 2:length(name)
Franklin McDaniel Harper Lynch Watkins
prev, curr = name[(i:i)-1], name[i:i]
Carlson Wheeler "Louis XVI"
next = i < length(name) ? name[(i:i)+1] : ""
» {
name = replaceat(name, i, vcat("EV", vowels), ["AF", "A", "A", "A", "A", "A"])
my $nysiis = nysiis no_suffix $_;
name = replaceat(name, i, "QZM", "GSN")
if $nysiis.chars > 6 {
$nysiisname .= subst:replaceat(name, rx/i, <after .**6> .+ /["KN", -> $/ { "[$/K"], ["N", };"C"])
name = replaceat(name, i, ["SCH", "PH"], ["SSS", "FF"])
if curr == "H" && (prev ∉ vowels || next ∉ vowels)
name = name[1:i-1] * prev * name[i+1:end]
end
if curr == "W" && prev ∈ vowels
name = name[1:i-1] * "A" * name[i+1:end]
end
if !isempty(key) && key[end:end] != name[i:i]
key *= name[i:i]
end
i += 1
end
key = replaceend(key, ["S", "AY", "A"], ["", "Y", ""])
return key1 * key
end
 
for name in ["Bishop", "Carlson", "Carr", "Chapman", "Franklin",
"Greene", "Harper", "Jacobs", "Larson", "Lawrence",
"Lawson", "Louis, XVI", "Lynch", "Mackenzie", "Matthews",
"McCormack", "McDaniel", "McDonald", "Mclaughlin", "Morrison",
"O'Banion", "O'Brien", "Richards", "Silva", "Watkins",
"Wheeler", "Willis", "brown, sr", "browne, III", "browne, IV",
"knight", "mitchell", "o'daniel"]
@printf("%15s: %s\n", name, nysiis(name))
end</syntaxhighlight>
 
{{out}}
<pre> Bishop: BASAP
Carlson: CARLSAN
Carr: CAR
Chapman: CAPNAN
Franklin: FRANCLAN
Greene: GRAN
Harper: HARPAR
Jacobs: JACAB
Larson: LARSAN
Lawrence: LARANC
Lawson: LASAN
Louis, XVI: LASXV
Lynch: LYNC
Mackenzie: MCANSY
Matthews: MATA
McCormack: MCARNAC
McDaniel: MCDANAL
McDonald: MCDANALD
Mclaughlin: MCLAGLAN
Morrison: MARASAN
O'Banion: OBANAN
O'Brien: OBRAN
Richards: RACARD
Silva: SALV
Watkins: WATCAN
Wheeler: WALAR
Willis: WALA
brown, sr: BRANSR
browne, III: BRAN
browne, IV: BRANAV
knight: NAGT
mitchell: MATCAL
o'daniel: ODANAL</pre>
 
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.1.2
 
val fStrs = listOf("MAC" to "MCC", "KN" to "N", "K" to "C", "PH" to "FF",
"PF" to "FF", "SCH" to "SSS")
 
val lStrs = listOf("EE" to "Y", "IE" to "Y", "DT" to "D", "RT" to "D",
"RD" to "D", "NT" to "D", "ND" to "D")
 
val mStrs = listOf("EV" to "AF", "KN" to "N", "SCH" to "SSS", "PH" to "FF")
 
val eStrs = listOf("JR", "JNR", "SR", "SNR")
 
fun Char.isVowel() = this in "AEIOU"
 
fun String.isRoman() = this.all { it in "IVX" }
fun nysiis(word: String): String {
if (word.isEmpty()) return word
var w = word.toUpperCase()
val ww = w.split(' ', ',')
if (ww.size > 1 && ww.last().isRoman()) w = w.dropLast(ww.last().length)
for (c in " ,'-") w = w.replace(c.toString(), "")
for (eStr in eStrs)
if (w.endsWith(eStr)) w = w.dropLast(eStr.length)
 
for (fStr in fStrs)
if (w.startsWith(fStr.first)) w = w.replaceFirst(fStr.first, fStr.second)
for (lStr in lStrs)
if (w.endsWith(lStr.first)) w = w.dropLast(2) + lStr.second
val key = StringBuilder().append(w[0])
w = w.drop(1)
for (mStr in mStrs) w = w.replace(mStr.first, mStr.second)
val sb = StringBuilder().append(key[0]).append(w)
var i = 1
var len = sb.length
while (i < len) {
when (sb[i]) {
in "EIOU" -> sb[i] = 'A'
'Q' -> sb[i] = 'G'
'Z' -> sb[i] = 'S'
'M' -> sb[i] = 'N'
'K' -> sb[i] = 'C'
'H' -> if (!sb[i - 1].isVowel() || (i < len - 1 && !sb[i + 1].isVowel())) sb[i] = sb[i - 1]
'W' -> if (sb[i - 1].isVowel()) sb[i] = 'A'
}
i++
}
if (sb[len - 1] == 'S') {
sb.setLength(len - 1)
len--
}
if (len > 1 && sb.substring(len - 2) == "AY") {
printf "%10s, %s\n", $_, $nysiis;
sb.setLength(len - 2)
}</lang>
sb.append("Y")
len--
}
if (len > 0 && sb[len - 1] == 'A') {
sb.setLength(len - 1)
len--
}
var prev = key[0]
for (j in 1 until len) {
val c = sb[j]
if (prev != c) {
key.append(c)
prev = c
}
}
return key.toString()
}
 
fun main(args:Array<String>) {
Output:
val names = listOf(
"Bishop", "Carlson", "Carr", "Chapman",
"Franklin", "Greene", "Harper", "Jacobs", "Larson", "Lawrence",
"Lawson", "Louis, XVI", "Lynch", "Mackenzie", "Matthews", "May jnr",
"McCormack", "McDaniel", "McDonald", "Mclaughlin", "Morrison",
"O'Banion", "O'Brien", "Richards", "Silva", "Watkins", "Xi",
"Wheeler", "Willis", "brown, sr", "browne, III", "browne, IV",
"knight", "mitchell", "o'daniel", "bevan", "evans", "D'Souza",
"Hoyle-Johnson", "Vaughan Williams", "de Sousa", "de la Mare II"
)
for (name in names) {
var name2 = nysiis(name)
if (name2.length > 6) name2 = "${name2.take(6)}(${name2.drop(6)})"
println("${name.padEnd(16)} : $name2")
}
}</syntaxhighlight>
 
{{out}}
<pre>
Bishop : BASAP
knight, NAGT
Carlson : CARLSA(N)
Carr : CAR
Chapman : CAPNAN
Franklin : FRANCL(AN)
Greene : GRAN
Harper : HARPAR
Jacobs : JACAB
Larson : LARSAN
Lawrence : LARANC
Lawson : LASAN
Louis, XVI : LA
Lynch : LYNC
Mackenzie : MCANSY
Matthews : MATA
May jnr : MY
McCormack : MCARNA(C)
McDaniel : MCDANA(L)
McDonald : MCDANA(LD)
Mclaughlin : MCLAGL(AN)
Morrison : MARASA(N)
O'Banion : OBANAN
O'Brien : OBRAN
Richards : RACARD
Silva : SALV
Watkins : WATCAN
Xi : X
Wheeler : WALAR
Willis : WAL
brown, sr : BRAN
browne, III : BRAN
browne, IV : BRAN
knight : NAGT
mitchell : MATCAL
o'daniel : ODANAL
bevan : BAFAN
evans : EVAN
D'Souza : DSAS
Hoyle-Johnson : HAYLAJ(ANSAN)
Vaughan Williams : VAGANW(ALAN)
de Sousa : DASAS
de la Mare II : DALANA(R)
</pre>
 
=={{header|Nim}}==
{{trans|Kotlin}}
<syntaxhighlight lang="nim">import strutils
 
const
FStrs = [("MAC", "MCC"), ("KN", "N"), ("K", "C"),
("PH", "FF"), ("PF", "FF"), ("SCH", "SSS")]
LStrs = [("EE", "Y"), ("IE", "Y"), ("DT", "D"),
("RT", "D"), ("RD", "D"), ("NT", "D"), ("ND", "D")]
MStrs = [("EV", "AF"), ("KN", "N"), ("SCH", "SSS"), ("PH", "FF")]
EStrs = ["JR", "JNR", "SR", "SNR"]
 
 
func isVowel(c: char): bool = c in {'A', 'E', 'I', 'O', 'U'}
 
func isRoman(s: string): bool = s.allCharsInSet({'I', 'V', 'X'})
 
 
func nysiis(word: string): string =
 
if word.len == 0: return
var word = word.toUpperAscii()
let fields = word.split({' ', ','})
if fields.len > 1:
let last = fields[^1]
if last.isRoman: word.setLen(word.len - last.len)
word = word.multiReplace((" ", ""), (",", ""), ("'", ""), ("-", ""))
for eStr in EStrs:
if word.endsWith(eStr): word.setLen(word.len - eStr.len)
for fStr in FStrs:
if word.startsWith(fStr[0]): word[0..fStr[0].high] = fStr[1]
for lStr in LStrs:
if word.endsWith(lStr[0]): word[^2..^1] = lStr[1]
 
result.add word[0]
word.delete(0..0)
for mStr in MStrs:
word = word.replace(mStr[0], mStr[1])
var s = result[0] & word
var len = s.len
for i in 1..<len:
case s[i]
of 'E', 'I', 'O', 'U': s[i] = 'A'
of 'Q': s[i] = 'G'
of 'Z': s[i] = 'S'
of 'M': s[i] = 'N'
of 'K': s[i] = 'C'
of 'H': (if not s[i-1].isVowel or i < len - 1 and not s[i+1].isVowel: s[i] = s[i-1])
of 'W': (if s[i-1].isVowel: s[i] = 'A')
else: discard
 
if s[len-1] == 'S':
s.setLen(len-1)
dec len
if len > 1 and s[len-2..len-1] == "AY":
s.delete(len-2..len-2)
dec len
if len > 0 and s[len-1] == 'A':
s.setLen(len-1)
dec len
 
var prev = result[0]
for i in 1..<len:
let c = s[i]
if prev != c:
result.add c
prev = c
 
 
const Names = ["Bishop", "Carlson", "Carr", "Chapman",
"Franklin", "Greene", "Harper", "Jacobs", "Larson", "Lawrence",
"Lawson", "Louis, XVI", "Lynch", "Mackenzie", "Matthews", "May jnr",
"McCormack", "McDaniel", "McDonald", "Mclaughlin", "Morrison",
"O'Banion", "O'Brien", "Richards", "Silva", "Watkins", "Xi",
"Wheeler", "Willis", "brown, sr", "browne, III", "browne, IV",
"knight", "mitchell", "o'daniel", "bevan", "evans", "D'Souza",
"Hoyle-Johnson", "Vaughan Williams", "de Sousa", "de la Mare II"]
 
for name1 in Names:
var name2 = nysiis(name1)
if name2.len > 6:
name2 = "$1($2)".format(name2[0..5], name2[6..^1])
echo name1.alignLeft(16), ": ", name2</syntaxhighlight>
 
{{out}}
<pre>Bishop : BASAP
Carlson : CARLSA(N)
Carr : CAR
Chapman : CAPNAN
Franklin : FRANCL(AN)
Greene : GRAN
Harper : HARPAR
Jacobs : JACAB
Larson : LARSAN
Lawrence : LARANC
Lawson : LASAN
Louis, XVI : LA
Lynch : LYNC
Mackenzie : MCANSY
Matthews : MATA
May jnr : MY
McCormack : MCARNA(C)
McDaniel : MCDANA(L)
McDonald : MCDANA(LD)
Mclaughlin : MCLAGL(AN)
Morrison : MARASA(N)
O'Banion : OBANAN
O'Brien : OBRAN
Richards : RACARD
Silva : SALV
Watkins : WATCAN
Xi : X
Wheeler : WALAR
Willis : WAL
brown, sr : BRAN
browne, III : BRAN
browne, IV : BRAN
knight : NAGT
mitchell : MATCAL
o'daniel : ODANAL
bevan : BAFAN
evans : EVAN
D'Souza : DSAS
Hoyle-Johnson : HAYLAJ(ANSAN)
Vaughan Williams: VAGANW(ALAN)
de Sousa : DASAS
de la Mare II : DALANA(R)</pre>
 
=={{header|Perl}}==
{{trans|Raku}}
<syntaxhighlight lang="perl">sub no_suffix {
my($name) = @_;
$name =~ s/\h([JS]R)|([IVX]+)$//i;
return uc $name;
}
 
sub nysiis {
my($name) = @_;
local($_) = uc $name;
 
s/[^A-Z]//g;
s/^MAC/MCC/;
s/^P[FH]/FF/;
s/^SCH/SSS/;
s/^KN/N/;
s/[IE]E$/Y/;
s/[DRN]T$/D/;
s/[RN]D$/D/;
s/(.)EV/$1AF/g;
s/(.)[AEIOU]+/$1A/g;
s/(.)Q/$1G/g;
s/(.)Z/$1S/g;
s/(.)M/$1N/g;
s/(.)KN/$1N/g;
s/(.)K/$1C/g;
s/(.)SCH/$1S/g;
s/(.)PF/$1F/g;
s/(.)K/$1C/g;
s/(.)H([^AEIOU])/$1$2/g;
s/([^AEIOU])H/$1/g;
s/(.)W/$1/g;
s/AY$/Y/;
s/S$//;
s/A$//;
s/(.)\1+/$1/g;
return $_;
}
 
for (
"knight", "mitchell", "o'daniel", "brown sr", "browne III",
"browne IV", "O'Banion", "Mclaughlin", "McCormack", "Chapman",
"Silva", "McDonald", "Lawson", "Jacobs", "Greene",
"O'Brien", "Morrison", "Larson", "Willis", "Mackenzie",
"Carr", "Lawrence", "Matthews", "Richards", "Bishop",
"Franklin", "McDaniel", "Harper", "Lynch", "Watkins",
"Carlson", "Wheeler", "Louis XVI"
) {
my $nysiis = nysiis no_suffix $_;
$nysiis =~ s/^(......)(.*)$/$1\[$2\]/ if length($nysiis) > 6;
printf "%10s, %s\n", $_, $nysiis;
}
</syntaxhighlight>
{{out}}
<pre style="height:35ex"> knight, NAGT
mitchell, MATCAL
o'daniel, ODANAL
Line 508 ⟶ 1,344:
Carlson, CARLSA[N]
Wheeler, WALAR
Louis XVI, L</pre>
 
=={{header|Phix}}==
{{trans|Go}}
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">isVowel</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">byte</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">byte</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"AEIOU"</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">isRoman</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">==</span> <span style="color: #008000;">""</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"IVX"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">nysiis</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">word</span> <span style="color: #0000FF;">==</span> <span style="color: #008000;">""</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">word</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">word</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ww</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split_any</span><span style="color: #0000FF;">(</span><span style="color: #000000;">word</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">", "</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ww</span><span style="color: #0000FF;">)></span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">last</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ww</span><span style="color: #0000FF;">[$]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">isRoman</span><span style="color: #0000FF;">(</span><span style="color: #000000;">last</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">word</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">last</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">word</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute_all</span><span style="color: #0000FF;">(</span><span style="color: #000000;">word</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">" ,'-"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">))</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">eStrs</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"JR"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"JNR"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SR"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SNR"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">eStrs</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">ei</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">eStrs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">lei</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ei</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">word</span><span style="color: #0000FF;">)></span><span style="color: #000000;">lei</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">lei</span><span style="color: #0000FF;">..$]=</span><span style="color: #000000;">ei</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">word</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">lei</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">fStrs</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"MAC"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"MCC"</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"KN"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"N"</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"K"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"C"</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"PH"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"FF"</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"PF"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"FF"</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"SCH"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"SSS"</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fStrs</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">fi</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rfi</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fStrs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">lfi</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fi</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">word</span><span style="color: #0000FF;">)></span><span style="color: #000000;">lfi</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">lfi</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">fi</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">word</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">lfi</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rfi</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">word</span><span style="color: #0000FF;">)>=</span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">l2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l2</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"EE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"IE"</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">word</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Y"</span>
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l2</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"DT"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"RT"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"RD"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"NT"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ND"</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">word</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"D"</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">initial</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">key</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">word</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">word</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
<span style="color: #000000;">word</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute_all</span><span style="color: #0000FF;">(</span><span style="color: #000000;">word</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"EV"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"KN"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"SCH"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"PH"</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AF"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"N"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SSS"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"FF"</span><span style="color: #0000FF;">})</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">sb</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">&</span><span style="color: #000000;">word</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">le</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sb</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">le</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">switch</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'E'</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">'I'</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">'O'</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">'U'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'A'</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'Q'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'G'</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'Z'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'S'</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'M'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'N'</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'K'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'C'</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'H'</span><span style="color: #0000FF;">:</span> <span style="color: #008080;">if</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">></span> <span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #008080;">not</span> <span style="color: #000000;">isVowel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]))</span>
<span style="color: #008080;">or</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;"><</span><span style="color: #000000;">le</span> <span style="color: #008080;">and</span> <span style="color: #008080;">not</span> <span style="color: #000000;">isVowel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]))</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'W'</span><span style="color: #0000FF;">:</span> <span style="color: #008080;">if</span> <span style="color: #000000;">isVowel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">switch</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">prev</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">initial</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">le</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">sb</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span> <span style="color: #0000FF;">!=</span> <span style="color: #000000;">c</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">key</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">c</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">c</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">)>=</span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">[$]</span> <span style="color: #0000FF;">==</span> <span style="color: #008000;">'S'</span> <span style="color: #008080;">then</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">[$</span> <span style="color: #0000FF;">..$]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">)>=</span><span style="color: #000000;">2</span> <span style="color: #008080;">and</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">==</span> <span style="color: #008000;">"AY"</span> <span style="color: #008080;">then</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">[$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Y"</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">)>=</span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">[$]</span> <span style="color: #0000FF;">==</span> <span style="color: #008000;">'A'</span> <span style="color: #008080;">then</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">[$</span> <span style="color: #0000FF;">..$]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">key</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Bishop"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"BASAP"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Carlson"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"CARLSAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Carr"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"CAR"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Chapman"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"CAPNAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Franklin"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"FRANCLAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Greene"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"GRAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Harper"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"HARPAR"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Jacobs"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"JACAB"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Larson"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"LARSAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Lawrence"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"LARANC"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Lawson"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"LASAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Louis, XVI"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"L"</span> <span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- (see note)</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Lynch"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"LYNC"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Mackenzie"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MCANSY"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Matthews"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MAT"</span> <span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- (see note)</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"May jnr"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MY"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"McCormack"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MCARNAC"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"McDaniel"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MCDANAL"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"McDonald"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MCDANALD"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Mclaughlin"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MCLAGLAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Morrison"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MARASAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"O'Banion"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"OBANAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"O'Brien"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"OBRAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Richards"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RACARD"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Silva"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SALV"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Watkins"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"WATCAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Wheeler"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"WALAR"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Willis"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"WAL"</span> <span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- (see note)</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Xi"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"X"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"bevan"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"BAFAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"brown, sr"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"BRAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"brown sr"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"BRAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"browne, III"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"BRAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"browne, IV"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"BRAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"evans"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"EVAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"knight"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"NAGT"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"mitchell"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MATCAL"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"o'daniel"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"ODANAL"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"D'Souza"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DSAS"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"de Sousa"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DASAS"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Hoyle-Johnson"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"HAYLAJANSAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"Vaughan Williams"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"VAGANWALAN"</span> <span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span> <span style="color: #008000;">"de la Mare II"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DALANAR"</span> <span style="color: #0000FF;">}</span> <span style="color: #0000FF;">}</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">errors</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span><span style="color: #000000;">expected</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">name2</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">nysiis</span><span style="color: #0000FF;">(</span><span style="color: #000000;">name</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">name2</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">expected</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">errors</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">name2</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">6</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">name2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%s(%s)"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">name2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">6</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">name2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">7</span><span style="color: #0000FF;">..$]})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%-16s : %s\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">name2</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"All tests completed, %d errors\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">errors</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
Note: After some careful consideration, I have decided that all three (see note) tests <i>are</i> in fact correct, or at least follow wp, specifically step 6 <i>before</i> step 7.
{{out}}
<pre>
All tests completed, 0 errors
</pre>
 
=={{header|Python}}==
A literal translation of the algorithm from the [[wp:New York State Identification and Intelligence System|Wikipedia article]].
<langsyntaxhighlight lang="python">import re
 
_vowels = 'AEIOU'
Line 566 ⟶ 1,561:
'knight', 'mitchell', "o'daniel"]
for name in names:
print('%15s: %s' % (name, nysiis(name)))</langsyntaxhighlight>
{{out}}
<pre> Bishop: BASAP
Line 601 ⟶ 1,596:
mitchell: MATCAL
o'daniel: ODANAL</pre>
 
=={{header|Racket}}==
 
{{trans|Python}}
This is a translation of [[Python]] to ensure that these results are consistent.
This allows them to be tested against a known output from another solution.
 
If any of the <code>check-equal?</code>s fails, it will print an error message.
None of them fail, so no output is seen.
 
I&rsquo;ve gone out of my way to number the rules &mdash; which may make it a little
verbose.
 
<syntaxhighlight lang="racket">#lang racket/base
(require racket/string racket/match)
(define (str-rplc-at str replacement start (end (string-length str)))
(string-append (substring str 0 start) replacement (substring str end)))
 
(define (split-on-commas s) (string-split s "," #:trim? #f))
 
(define (str-rplc-at* fxt pos . more)
(match more
[(list (app split-on-commas froms) (app split-on-commas tos) even-more ...)
(define txt-maybe
(for/first ((f froms) (t tos) #:when (string-prefix? (substring fxt pos) f))
(str-rplc-at fxt t pos (+ pos (string-length f)))))
(apply str-rplc-at* (or txt-maybe fxt) pos even-more)]
[_ fxt]))
 
(define (str-rplc-end* txf . more)
(match more
[(list (app split-on-commas froms) (app split-on-commas tos) even-more ...)
(define txt-maybe
(for/first ((f froms) (t tos) #:when (string-suffix? txf f))
(str-rplc-at txf t (- (string-length txf) (string-length f)))))
(apply str-rplc-end* (or txt-maybe txf) even-more)]
[_ txf]))
 
(define vowels '("A" "E" "I" "O" "U"))
(define (vowel? s) (member s vowels))
 
;; ---------------------------------------------------------------------------------------------------
(define (normalise n) (regexp-replace* #px"\\W" (string-upcase n) ""))
 
(define (r:1 n) (str-rplc-at* n 0 "MAC,KN,K,PH,PF,SCH" "MCC,N,C,FF,FF,SSS"))
 
(define (r:2 n) (str-rplc-end* n "EE,IE,DT,RT,RD,NT,ND" "Y,Y,D,D,D,D,D"))
 
(define (r:3/4 in)
(define (loop-4 name-4.1 key-3 i)
(cond
[(< i (string-length name-4.1))
(define name-4.2/3/4
(str-rplc-at* name-4.1 i "EV,A,E,I,O,U" "AF,A,A,A,A,A" #|4.1|# "Q,Z,M" "G,S,N" #|4.2|#
"KN,K" "N,C" #|4.3|# "SCH,PH" "SSS,FF" #|4.4|#))
(define name-4.5/6
(match-let ([(or (regexp "^(.)(.)(.)" (list n_1 n n1_))
(regexp "^(.)(.)" (list (app (λ _ "") n1_) n_1 n)))
(substring name-4.1 (sub1 i))])
(match n
["H" #:when (or (not (vowel? n_1)) (not (vowel? n1_)))
(str-rplc-at name-4.2/3/4 n_1 i (add1 i))] ; 4.5
["W" #:when (vowel? n_1) (str-rplc-at name-4.2/3/4 "A" i (add1 i))] ; 4.6
[_ name-4.2/3/4])))
(define name-4.6_i (substring name-4.5/6 i (add1 i)))
(define key-4.7 (if (string=? name-4.6_i (substring key-3 (sub1 (string-length key-3))))
key-3 (string-append key-3 name-4.6_i)))
(loop-4 name-4.5/6 key-4.7 (add1 i))]
[else key-3]))
(loop-4 in (substring in 0 1) 1))
 
(define (r:5/6/7/8 n) (str-rplc-end* n "S,AY,A" ",Y,"))
 
(define r:9 (match-lambda [(regexp #px"^(.{6})(.+)" (list _ l r)) (format "~a[~a]" l r)] [n n]))
 
(define nysiis (apply compose (reverse (list normalise r:1 r:2 r:3/4 r:5/6/7/8 r:9))))
 
(module+ test
(require rackunit)
(define names
(list "Bishop" "Carlson" "Carr" "Chapman" "Franklin" "Greene" "Harper" "Jacobs" "Larson"
"Lawrence" "Lawson" "Louis, XVI" "Lynch" "Mackenzie" "Matthews" "McCormack" "McDaniel"
"McDonald" "Mclaughlin" "Morrison" "O'Banion" "O'Brien" "Richards" "Silva" "Watkins"
"Wheeler" "Willis" "brown, sr" "browne, III" "browne, IV" "knight" "mitchell" "o'daniel"))
 
(define py-nysiis-names ; results from python (with [] added)
(list "BASAP" "CARLSA[N]" "CAR" "CAPNAN" "FRANCL[AN]" "GRAN" "HARPAR" "JACAB" "LARSAN" "LARANC"
"LASAN" "LASXV" "LYNC" "MCANSY" "MATA" "MCARNA[C]" "MCDANA[L]" "MCDANA[LD]" "MCLAGL[AN]"
"MARASA[N]" "OBANAN" "OBRAN" "RACARD" "SALV" "WATCAN" "WALAR" "WALA" "BRANSR" "BRAN"
"BRANAV" "NAGT" "MATCAL" "ODANAL"))
 
(for ((n names) (p py-nysiis-names))
(check-equal? (nysiis n) p (format "(nysiis ~s) = ~s" n p))))</syntaxhighlight>
 
=={{header|Raku}}==
(formerly Perl 6)
{{Works with|rakudo|2017.05}}
This implementation removes common name suffixes similar to the reference implementation, even though it is not specified in the task description or on the linked [[wp:New York State Identification and Intelligence System|NYSIIS]] page. This algorithm isn't too friendly to certain French kings. :)
 
<syntaxhighlight lang="raku" line>sub no_suffix ($name) {
$name.uc.subst: /\h (<[JS]>R) | (<[IVX]>+) $/, '';
}
 
sub nysiis ($name is copy) {
given $name .= uc {
s:g/<-[A..Z]>//;
s/^MAC/MCC/;
s/^P<[FH]>/FF/;
s/^SCH/SSS/;
s/^KN/N/;
s/<[IE]>E$ /Y/;
s/<[DRN]>T$ /D/;
s/<[RN]>D$ /D/;
s:c(1):g/EV/AF/;
s:c(1):g/<[AEIOU]>+/A/;
s:c(1):g/Q/G/;
s:c(1):g/Z/S/;
s:c(1):g/M/N/;
s:c(1):g/KN/N/;
s:c(1):g/K/C/;
s:c(1):g/SCH/S/;
s:c(1):g/PF/F/;
s:c(1):g/K/C/;
s:c(1):g/H(<-[AEIOU]>)/$0/;
s:g/(<-[AEIOU]>)H/$0/;
s:g/(.)W/$0/;
s/ AY$ /Y/;
s/ S$ //;
s/ A$ //;
s:g/ (.)$0+ /$0/;
}
return $name;
}
 
 
for «
knight mitchell "o'daniel" "brown sr" "browne III"
"browne IV" "O'Banion" Mclaughlin McCormack Chapman
Silva McDonald Lawson Jacobs Greene
"O'Brien" Morrison Larson Willis Mackenzie
Carr Lawrence Matthews Richards Bishop
Franklin McDaniel Harper Lynch Watkins
Carlson Wheeler "Louis XVI"
» {
my $nysiis = nysiis no_suffix $_;
if $nysiis.chars > 6 {
$nysiis .= subst: rx/ <after .**6> .+ /, -> $/ { "[$/]" };
}
printf "%10s, %s\n", $_, $nysiis;
}</syntaxhighlight>
 
Output:
 
<pre>
knight, NAGT
mitchell, MATCAL
o'daniel, ODANAL
brown sr, BRAN
browne III, BRAN
browne IV, BRAN
O'Banion, OBANAN
Mclaughlin, MCLAGL[AN]
McCormack, MCARNA[C]
Chapman, CAPNAN
Silva, SALV
McDonald, MCDANA[LD]
Lawson, LASAN
Jacobs, JACAB
Greene, GRAN
O'Brien, OBRAN
Morrison, MARASA[N]
Larson, LARSAN
Willis, WAL
Mackenzie, MCANSY
Carr, CAR
Lawrence, LARANC
Matthews, MAT
Richards, RACARD
Bishop, BASAP
Franklin, FRANCL[AN]
McDaniel, MCDANA[L]
Harper, HARPAR
Lynch, LYNC
Watkins, WATCAN
Carlson, CARLSA[N]
Wheeler, WALAR
Louis XVI, L
</pre>
 
=={{header|REXX}}==
This REXX version allows a blank to be inserted into names by using an underscore or underbar character &nbsp; [ <big><big>'''_'''</big></big> ].
<br>Code was added to the REXX program to allow various titles.
<br>Any title ending in a period is ignored as well as some Roman numeral titles.
<br>An "extra" &nbsp; '''RETURN''' &nbsp; statement (at the end of the '''NYSIIS''' subroutine) was included to show how to restrict the key to six characters.
<lang rexx>/*REXX program implements the NYSIIS phonetic algorithm for names. */
names="Bishop brown_sr browne_III browne_IV Carlson Carr Chapman D'Souza de_Sousa Franklin",
"Greene Harper Hoyle-Johnson Jacobs knight Larson Lawrence Lawson Louis_XVI Lynch",
"Mackenzie Marshall,ESQ Matthews McCormack McDaniel McDonald Mclaughlin mitchell Morrison",
"O'Banion O'Brien o'daniel Richards Silva Vaughan_Williams Watkins Wheeler Willis Xavier,MD."
arg z; if z='' then z=names /*get optional list of names. */
 
Code was added to the REXX program to allow various titles.
do i=1 for words(z) /*process each name in the list. */
xx=translate(word(z,i),,'_') /*reconstitute any blanks. */
say right(xx,30) ' ──► ' nysiis(xx) /*show and tell stuff. */
end /*i*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────NYSIIS subroutine───────────────────*/
nysiis: procedure; arg x; x=space(x); x=translate(x,,','); w=words(x)
lw=word(x,words(x)) /*pick off the last word in name.*/
titles = 'ESQ JNR JR SNR SR' /* [↓] is the last word special?*/
if w\==1 then if pos('IL',lw)==0 then /*disallow IL as Roman#*/
if right(lw,1)=='.' |, /*Sr. Jr. Esq. ... ?*/
datatype(left(lw,1),'W') |, /*2nd 3rd 4th ... ?*/
verify(lw,'IVXL')==0 |, /*Roman numeral suffix?*/
wordpos(x,titles)\==0 then x=subword(x,1,w-1)
x=space(x,0) /*remove all whitespace from name*/
if left(x,3)=='MAC' then x='MCC'substr(x,4)
if left(x,2)=='KN' then x= 'N'substr(x,3)
if left(x,1)=='K' then x= 'C'substr(x,2)
if left(x,2)=='PH' | left(x,2)=='PF' then x= 'FF'substr(x,3)
if left(x,3)=='SCH' then x='SSS'substr(x,4)
r2=right(x,2)
if wordpos(r2,'EE IE') \==0 then x=left(x,length(x)-2)"Y"
if wordpos(r2,'DT RT RD NT ND')\==0 then x=left(x,length(x)-2)"D"
key=left(x,1)
 
Any post-nominal letters (generational, honorific, professional,or other) &nbsp; ending in a period is ignored as well as most Roman numeral letters.
do j=2 to length(x); c2=substr(x,j,2); c=left(c2,1)
if \datatype(c,'Upper') then iterate /*Not a Latin char? Ignore it*/
if c2=='EV' then x=overlay("F",x,j+1)
else x=overlay(translate(c,'AAAAGSN',"EIOUQZM"),x,j)
if c2=='KN' then x=left(x,j-1)"N"substr(x,j+1)
else if c1=="K" then x=overlay('C',x,j)
c3=substr(x,j,3)
if c3=='SCH' then x=overlay("SSS",x,j)
c2=substr(x,j,2)
if c2=='PH' then x=overlay("FF",x,j)
c=substr(x,j,1); p=substr(x,j-1,1); n=substr(x,j+1,1)
if c=='H' then if \vowel(p) | \vowel(n) then x=overlay(p,x,j)
c=substr(x,j,1); p=substr(x,j-1,1)
if c=='W' then if vowel(p) then x=overlay("A",x,j)
c=substr(x,j,1)
if c\==right(key,1) then key=key||c
end /*j*/
 
If the rule of only returning (up to) six characters is to be enforced, then the last REXX statement should be
if right(key,1)=='S' then key=left(key, max(1, length(key)-1))
replaced with:
if right(key,2)=='AY' then key=left(key, length(key)-2)"Y"
<syntaxhighlight lang="rexx">return strip( left(key, 6) ) /*return the leftmost six characters. */</syntaxhighlight>
if right(key,1)=='A' then key=left(key, max(1, length(key)-1))
<syntaxhighlight lang="rexx">/*REXX program implements the NYSIIS phonetic algorithm (for various test names). */
@@= "Bishop brown_sr browne_III browne_IV Carlson Carr Chapman D'Souza de_Sousa Franklin",
"Greene Harper Hoyle-Johnson Jacobs knight Larson Lawrence Lawson Louis_XVI Lynch",
"Mackenzie Marshall,ESQ Matthews McCormack McDaniel McDonald Mclaughlin mitchell Morrison",
"O'Banion O'Brien o'daniel Richards Silva Vaughan_Williams Watkins Wheeler Willis Xavier,MD."
parse upper arg z; if z='' then z= @@ /*obtain optional name list from the CL*/
 
return strip(key) do i=1 for words(z) /*return the whole key. /*process each name (word) in the list.*/
return strip(left(key, 6)) xx= translate( word(z, i), , '_') /*returnreconstitute leftmostany sixblanks chars.using TRANS. */
say right(xx, 35) ' ──► ' nysiis(xx) /*display some stuff to the terminal. */
/*──────────────────────────────────VOWEL subroutine────────────────────*/
end /*i*/
vowel: return pos(arg(1), 'AEIOU') \== 0</lang>
exit 0 /*stick a fork in it, we're all done. */
'''output''' when using the default input(s):
/*──────────────────────────────────────────────────────────────────────────────────────*/
<pre style="overflow:scroll">
$: p= substr(x,j-1,1) /*prev*/; n= substr(x,j+1,1) /*next*/; return substr(x,j,arg(1))
Bishop ──► BASAP
vowel: return pos(arg(1), 'AEIOUaeiou') \== 0 /*returns 1 if the argument has a vowel*/
brown sr ──► BRANSR
/*──────────────────────────────────────────────────────────────────────────────────────*/
browne III ──► BRAN
nysiis: procedure; arg x; x= space( translate(x, , ',')) /*elide commas, excess blanks*/
browne IV ──► BRAN
w= words(x); Lw= word(x, w) Carlson ──► /*pick CARLSANoff the last word in name list. */
@titles= 'ESQ JNR JR SNR SR' Carr/* [↓] ──► last CARword post─nominal letters?*/
if w\==1 then if pos('IL', lw)==0 then Chapman ──► CAPNAN /*disallow IL as Roman #.*/
D'Souza ──► if DSASpos(., x)\==0 |, /*Sr. Jr. Esq. ··· ? */
de Sousa ──► DASAS datatype( left(Lw, 1), 'W') |, /*2nd 3rd 4th ··· ? */
Franklin ──► FRANKLAN verify(Lw, 'IVXL') ==0 |, /*Roman numeral suffix? */
Greene ──► GRAN wordpos(x, @titles)\==0 then x= subword(x, 1, w-1)
x= space(x, 0) Harper ──► HARPAR /*remove all whitespace from the name. */
if left(x, 3)=='MAC' then x= "MCC"substr(x, 4) /*start with MAC ? */
Hoyle-Johnson ──► HAYLAJANSAN
if left(x, 2)=='KN' then x= Jacobs ──►"N"substr(x, 3) JACAB /* " " KN ? */
if left(x, 1)=='K' then knightx= ──► "C"substr(x, NAGT2) /* " " K ? */
if left(x, 2)=='PH' | left(x,2)=="PF" then x= 'FF'substr(x, 3) /* " " Larson ──► LARSANPH,PF?*/
if left(x, 3)=='SCH' then Lawrencex= "SSS"substr(x, ──►4) LARANC /* " " SCH ? */
r2= right(x, 2)
Lawson ──► LASAN
if wordpos(r2, 'EE IE') \==0 then x= left(x, length(x)-2)"Y" /*ends with Louis··· XVI ──► L?*/
if wordpos(r2, 'DT RT RD NT ND')\==0 then x= left(x, length(x)-2)"D" /* " " " Lynch ──► LYNC"*/
key= left(x, 1) Mackenzie ──► MCKANSY /*use first char.*/
 
Marshall,ESQ ──► MARSALASG
do j=2 to length(x); if \datatype($(1), 'U') then iterate /*¬ Latin letter? Skip it*/
Matthews ──► MAT
if $(2)=='EV' then x= overlay("F", x, j+1) McCormack ──► MCARNACK /*have an EV ? Use F */
else x= overlay( McDanieltranslate( $(1), ──►'AAAAGSN', "EIOUQZM"), MCDANAL x, j)
if $(2)=='KN' then x= left(x, j-1)"N"substr(x, j+1) /*have a McDonaldKN ? ──► MCDANALDUse N */
else Mclaughlinif $(1)=="K" ──► then MCLAGLANx= overlay('C',x,j) /* " " K ? Use C */
if $(3)=='SCH' then x= overlay("SSS", x, j) mitchell ──► MATCAL/* " " SCH? Use SSS*/
if $(2)=='PH' then x= overlay("FF", x, j) Morrison ──► MARASAN /* " " PH ? Use FF */
if $(1)=='H' then if \vowel(p) | \vowel(n) then x= overlay( p , x, j)
O'Banion ──► OBANAN
if $(1)=='W' then if vowel(p) O'Brien ──►then x= overlay("A", x, OBRANj)
if $(1)\== right(key, 1) o'daniel ──► ODANAL then key= key || $(1) /*append to KEY.*/
end /*j*/
Richards ──► RACARD
Silva ──► SALV /* [↓] elide: */
if right(key, 1)=='S' then key= left(key, max(1, length(key) -1)) /*ending S */
Vaughan Williams ──► VAGANWALAN
if right(key, 2)=='AY' then key= left(key, length(key) -2)"Y" /* " Watkins A ──►in WATKANAY*/
if right(key, 1)=='A' then key= left(key, max(1, length(key) -1)) /* " A Wheeler ──► WALAR*/
return strip(key) Willis ──► WAL /*return the whole key (all of it). */</syntaxhighlight>
{{out|output|text=&nbsp; when using the default input:}}
Xavier,MD. ──► XAVAR
<pre>
Bishop ──► BASAP
brown sr ──► BRANSR
browne III ──► BRAN
browne IV ──► BRAN
Carlson ──► CARLSAN
Carr ──► CAR
Chapman ──► CAPNAN
D'Souza ──► DSAS
de Sousa ──► DASAS
Franklin ──► FRANCLAN
Greene ──► GRAN
Harper ──► HARPAR
Hoyle-Johnson ──► HAYLAJANSAN
Jacobs ──► JACAB
knight ──► NAGT
Larson ──► LARSAN
Lawrence ──► LARANC
Lawson ──► LASAN
Louis XVI ──► L
Lynch ──► LYNC
Mackenzie ──► MCANSY
Marshall,ESQ ──► MARSALASG
Matthews ──► MAT
McCormack ──► MCARNAC
McDaniel ──► MCDANAL
McDonald ──► MCDANALD
Mclaughlin ──► MCLAGLAN
mitchell ──► MATCAL
Morrison ──► MARASAN
O'Banion ──► OBANAN
O'Brien ──► OBRAN
o'daniel ──► ODANAL
Richards ──► RACARD
Silva ──► SALV
Vaughan Williams ──► VAGANWALAN
Watkins ──► WATCAN
Wheeler ──► WALAR
Willis ──► WAL
Xavier,MD. ──► XAVAR
</pre>
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">proc nysiis {name {truncate false}} {
# Normalize to first word, uppercased, without non-letters
set name [regsub -all {[^A-Z]+} [string toupper [regexp -inline {\S+} $name]] ""]
Line 736 ⟶ 1,917:
}
return $name
}</langsyntaxhighlight>
Demonstrating:
<langsyntaxhighlight lang="tcl">foreach name {
knight mitchell "o'daniel" "brown sr" "browne III"
"browne IV" "O'Banion" Mclaughlin McCormack Chapman
Line 748 ⟶ 1,929:
} {
puts "$name -> [nysiis $name]"
}</langsyntaxhighlight>
{{out}}
<pre>
Line 784 ⟶ 1,965:
Wheeler -> WHALAR
Louis XVI -> L
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-str}}
{{libheader|Wren-pattern}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./str" for Str
import "./pattern" for Pattern
import "./fmt" for Fmt
 
var fStrs = [["MAC", "MCC"], ["KN", "N"], ["K", "C"], ["PH", "FF"], ["PF", "FF"], ["SCH", "SSS"]]
var lStrs = [["EE", "Y"], ["IE", "Y"], ["DT", "D"], ["RT", "D"], ["RD", "D"], ["NT", "D"], ["ND", "D"]]
var mStrs = [["EV", "AF"], ["KN", "N"], ["SCH", "SSS"], ["PH", "FF"]]
var eStrs = ["JR", "JNR", "SR", "SNR"]
 
var isVowel = Fn.new { |c| "AEIOU".contains(c) }
 
var isRoman = Fn.new { |s| s.all { |c| "IVX".contains(c) } }
 
var splitter = Pattern.new("[ |,]")
 
var nysiis = Fn.new { |word|
if (word == "") return word
var w = Str.upper(word)
var ww = splitter.splitAll(w)
if (ww.count > 1 && isRoman.call(ww[-1])) w = w[0...w.count-ww[-1].count]
for (c in " ,'-") w = w.replace(c, "")
for (eStr in eStrs) {
if (w.endsWith(eStr)) w = w[0...w.count-eStr.count]
}
for (fStr in fStrs) {
if (w.startsWith(fStr[0])) w = fStr[1] + w[fStr[0].count..-1]
}
for (lStr in lStrs) {
if (w.endsWith(lStr[0])) w = w[0..-3] + lStr[1]
}
var key = w[0]
w = w[1..-1]
for (mStr in mStrs) w = w.replace(mStr[0], mStr[1])
var sb = (key[0] + w).toList
var i = 1
var len = sb.count
while (i < len) {
if ("EIOU".contains(sb[i])) {
sb[i] = "A"
} else if (sb[i] == "Q") {
sb[i] = "G"
} else if (sb[i] == "Z") {
sb[i] = "S"
} else if (sb[i] == "M") {
sb[i] = "N"
} else if (sb[i] == "K") {
sb[i] = "C"
} else if (sb[i] == "H") {
if (!isVowel.call(sb[i-1]) || (i < len-1 && !isVowel.call(sb[i+1]))) sb[i] = sb[i-1]
} else if (sb[i] == "W") {
if (isVowel.call(sb[i-1])) sb[i] = "A"
}
i = i + 1
}
if (sb[len-1] == "S") {
sb = sb[0...len-1]
len = len - 1
}
if (len > 1 && Str.sub(sb.join(""), len-2..-1) == "AY") {
sb = sb[0...len-2]
sb = sb + ["Y"]
len = len -1
}
if (len > 0 && sb[len-1] == "A") {
sb = sb[0...len-1]
len = len - 1
}
var prev = key[0]
for (j in 1...len) {
var c = sb[j]
if (prev != c) {
key = key + c
prev = c
}
}
return key
}
 
var names = [
"Bishop", "Carlson", "Carr", "Chapman",
"Franklin", "Greene", "Harper", "Jacobs", "Larson", "Lawrence",
"Lawson", "Louis, XVI", "Lynch", "Mackenzie", "Matthews", "May jnr",
"McCormack", "McDaniel", "McDonald", "Mclaughlin", "Morrison",
"O'Banion", "O'Brien", "Richards", "Silva", "Watkins", "Xi",
"Wheeler", "Willis", "brown, sr", "browne, III", "browne, IV",
"knight", "mitchell", "o'daniel", "bevan", "evans", "D'Souza",
"Hoyle-Johnson", "Vaughan Williams", "de Sousa", "de la Mare II"
]
 
for (name in names) {
var name2 = nysiis.call(name)
if (name2.count > 6) name2 = Fmt.swrite("$s($s)", name2[0..5], name2[6..-1])
Fmt.print("$-16s : $s", name, name2)
}</syntaxhighlight>
 
{{out}}
<pre>
Bishop : BASAP
Carlson : CARLSA(N)
Carr : CAR
Chapman : CAPNAN
Franklin : FRANCL(AN)
Greene : GRAN
Harper : HARPAR
Jacobs : JACAB
Larson : LARSAN
Lawrence : LARANC
Lawson : LASAN
Louis, XVI : LA
Lynch : LYNC
Mackenzie : MCANSY
Matthews : MATA
May jnr : MY
McCormack : MCARNA(C)
McDaniel : MCDANA(L)
McDonald : MCDANA(LD)
Mclaughlin : MCLAGL(AN)
Morrison : MARASA(N)
O'Banion : OBANAN
O'Brien : OBRAN
Richards : RACARD
Silva : SALV
Watkins : WATCAN
Xi : X
Wheeler : WALAR
Willis : WAL
brown, sr : BRAN
browne, III : BRAN
browne, IV : BRAN
knight : NAGT
mitchell : MATCAL
o'daniel : ODANAL
bevan : BAFAN
evans : EVAN
D'Souza : DSAS
Hoyle-Johnson : HAYLAJ(ANSAN)
Vaughan Williams : VAGANW(ALAN)
de Sousa : DASAS
de la Mare II : DALANA(R)
</pre>
 
=={{header|zkl}}==
{{trans|Python}}
<syntaxhighlight lang="zkl">fcn replaceAt(text,pos,fromList,toList){
foreach f,t in (fromList.zip(toList)){
if(0==text[pos,*].find(f)) return(text.set(pos,f.len(),t));
}
text
}
fcn replaceEnd(text,fromList,toList){
foreach f,t in (fromList.zip(toList)){
if ((text.len() - f.len())==text.rfind(f)) return(text.set(-f.len(),*,t));
}
text
}
fcn nysiis(name){
vowels := "AEIOU";
// name = name.filter(fcn(c){ (not c.isSpace()) }).toUpper();
name = name.toUpper().filter("matches","[A-Z]");
name = replaceAt(name,0, T("MAC", "KN", "K", "PH", "PF", "SCH"),
T("MCC", "N", "C", "FF", "FF", "SSS"));
name = replaceEnd(name,T("EE", "IE", "DT", "RT", "RD", "NT", "ND"),
T("Y", "Y", "D", "D", "D", "D", "D"));
key := name[0];
foreach i in ([1 .. name.len()-1]){
n_1,n,n1b:= name[i-1], name[i], name[i+1,1]; // "" if i+1>len
name = replaceAt(name,i, T("EV").extend(vowels.split("")),
T("AF","A","A","A","A","A"));
name = replaceAt(name,i, T("Q","Z","M"), T("G","S","N"));
name = replaceAt(name,i, T("KN", "K"), T("N", "C"));
name = replaceAt(name,i, T("SCH", "PH"), T("SSS", "FF"));
if (n=="H" and (not vowels.holds(n_1) or not vowels.holds(n1b)))
name = name.set(i,1,n_1);
if (n=="W" and vowels.holds(n_1)) name = name.set(i,1,"A");
if (key[-1,1] != name[i]) key += name[i];
}
replaceEnd(key, T("S", "AY", "A"), T("", "Y", ""));
}</syntaxhighlight>
<syntaxhighlight lang="zkl">names := T("Bishop", "Carlson", "Carr", "Chapman",
"Franklin", "Greene", "Harper", "Jacobs", "Larson", "Lawrence",
"Lawson", "Louis, XVI", "Lynch", "Mackenzie", "Matthews",
"McCormack", "McDaniel", "McDonald", "Mclaughlin", "Morrison",
"O'Banion", "O'Brien", "Richards", "Silva", "Watkins",
"Wheeler", "Willis", "brown, sr", "browne, III", "browne, IV",
"knight", "mitchell", "o'daniel");
foreach name in (names){ println("%11s: %s".fmt(name, nysiis(name))) }</syntaxhighlight>
{{out}}
<pre>
Bishop: BASAP
Carlson: CARLSAN
Carr: CAR
Chapman: CAPNAN
Franklin: FRANCLAN
Greene: GRAN
Harper: HARPAR
Jacobs: JACAB
Larson: LARSAN
Lawrence: LARANC
Lawson: LASAN
Louis, XVI: LASXV
Lynch: LYNC
Mackenzie: MCANSY
Matthews: MATA
McCormack: MCARNAC
McDaniel: MCDANAL
McDonald: MCDANALD
Mclaughlin: MCLAGLAN
Morrison: MARASAN
O'Banion: OBANAN
O'Brien: OBRAN
Richards: RACARD
Silva: SALV
Watkins: WATCAN
Wheeler: WALAR
Willis: WALA
brown, sr: BRANSR
browne, III: BRAN
browne, IV: BRANAV
knight: NAGT
mitchell: MATCAL
o'daniel: ODANAL
</pre>
9,482

edits