///|
fn nysiis_is_vowel(letter : UInt16) -> Bool {
letter == 65 || letter == 69 || letter == 73 || letter == 79 || letter == 85
}
///|
fn copy_ascii_range(value : String, start : Int, end : Int) -> String {
let mut out = ""
for i = start; i < end; i = i + 1 {
out = out + value[i].unsafe_to_char().to_string()
}
out
}
///|
fn replace_prefix(
value : String,
consumed : Int,
replacement : String,
) -> String {
replacement + copy_ascii_range(value, consumed, value.length())
}
///|
fn replace_suffix(
value : String,
consumed : Int,
replacement : String,
) -> String {
copy_ascii_range(value, 0, value.length() - consumed) + replacement
}
///|
fn prepare_nysiis(value : String) -> String {
let mut prepared = value
if prepared.length() >= 3 &&
prepared[0] == 77 &&
prepared[1] == 65 &&
prepared[2] == 67 {
prepared = replace_prefix(prepared, 3, "MCC")
} else if prepared.length() >= 2 && prepared[0] == 75 && prepared[1] == 78 {
prepared = replace_prefix(prepared, 2, "NN")
} else if prepared[0] == 75 {
prepared = replace_prefix(prepared, 1, "C")
} else if prepared.length() >= 2 &&
prepared[0] == 80 &&
(prepared[1] == 72 || prepared[1] == 70) {
prepared = replace_prefix(prepared, 2, "FF")
} else if prepared.length() >= 3 &&
prepared[0] == 83 &&
prepared[1] == 67 &&
prepared[2] == 72 {
prepared = replace_prefix(prepared, 3, "SSS")
}
let length = prepared.length()
if length >= 2 &&
(prepared[length - 2] == 69 || prepared[length - 2] == 73) &&
prepared[length - 1] == 69 {
prepared = replace_suffix(prepared, 2, "Y")
} else if length >= 2 &&
(
(prepared[length - 2] == 68 && prepared[length - 1] == 84) ||
(prepared[length - 2] == 82 && prepared[length - 1] == 84) ||
(prepared[length - 2] == 82 && prepared[length - 1] == 68) ||
(prepared[length - 2] == 78 && prepared[length - 1] == 84) ||
(prepared[length - 2] == 78 && prepared[length - 1] == 68)
) {
prepared = replace_suffix(prepared, 2, "D")
}
prepared
}
///|
/// Encodes ASCII letters with the untruncated NYSIIS rules.
pub fn nysiis(input : String) -> String {
let letters = normalize_ascii_letters(input)
if letters.length() == 0 {
return ""
}
let prepared = prepare_nysiis(letters)
let chars : Array[UInt16] = []
for i = 0; i < prepared.length(); i = i + 1 {
chars.push(prepared[i])
}
let key : Array[UInt16] = [chars[0]]
for i = 1; i < chars.length(); i = i + 1 {
let previous = chars[i - 1]
let current = chars[i]
let next = if i + 1 < chars.length() { chars[i + 1] } else { 32 }
let after_next = if i + 2 < chars.length() { chars[i + 2] } else { 32 }
if current == 69 && next == 86 {
chars[i] = 65
chars[i + 1] = 70
} else if nysiis_is_vowel(current) {
chars[i] = 65
} else if current == 81 {
chars[i] = 71
} else if current == 90 {
chars[i] = 83
} else if current == 77 {
chars[i] = 78
} else if current == 75 {
if next == 78 {
chars[i] = 78
chars[i + 1] = 78
} else {
chars[i] = 67
}
} else if current == 83 && next == 67 && after_next == 72 {
chars[i] = 83
chars[i + 1] = 83
chars[i + 2] = 83
} else if current == 80 && next == 72 {
chars[i] = 70
chars[i + 1] = 70
} else if current == 72 &&
(!nysiis_is_vowel(previous) || !nysiis_is_vowel(next)) {
chars[i] = previous
} else if current == 87 && nysiis_is_vowel(previous) {
chars[i] = previous
}
if chars[i] != chars[i - 1] {
key.push(chars[i])
}
}
let mut end = key.length()
if end > 1 && key[end - 1] == 83 {
end = end - 1
}
if end > 2 && key[end - 2] == 65 && key[end - 1] == 89 {
key[end - 2] = 89
end = end - 1
}
if end > 1 && key[end - 1] == 65 {
end = end - 1
}
let mut result = ""
for i = 0; i < end; i = i + 1 {
result = result + key[i].unsafe_to_char().to_string()
}
result
}