///|
fn match_rating_remove_vowels(input : String) -> String {
if input.length() == 0 {
return ""
}
let first = input[0]
let mut output = ""
for i = 0; i < input.length(); i = i + 1 {
let code = input[i]
if !encoder_ascii_is_vowel(code) || code == 89 {
output = output + code.unsafe_to_char().to_string()
}
}
if encoder_ascii_is_vowel(first) && first != 89 {
first.unsafe_to_char().to_string() + output
} else {
output
}
}
///|
fn match_rating_collapse_doubles(input : String) -> String {
let mut output = ""
let mut previous : UInt16 = 0
for i = 0; i < input.length(); i = i + 1 {
let code = input[i]
if code != previous {
output = output + code.unsafe_to_char().to_string()
}
previous = code
}
output
}
///|
fn match_rating_reduce(input : String) -> String {
if input.length() > 6 {
ascii_slice(input, 0, 3) +
ascii_slice(input, input.length() - 3, input.length())
} else {
input
}
}
///|
/// Generates the at-most-six-character Match Rating codex.
pub fn match_rating_codex(input : String) -> String {
let letters = normalize_ascii_letters(input)
if letters.length() == 0 {
return ""
}
match_rating_reduce(
match_rating_collapse_doubles(match_rating_remove_vowels(letters)),
)
}
///|
fn match_rating_minimum(sum_length : Int) -> Int {
if sum_length <= 4 {
5
} else if sum_length <= 7 {
4
} else if sum_length <= 11 {
3
} else if sum_length == 12 {
2
} else {
1
}
}
///|
fn match_rating_unmatched(chars : Array[UInt16]) -> Int {
let mut count = 0
for code in chars {
if code != 32 {
count = count + 1
}
}
count
}
///|
fn match_rating_elimination_score(left : String, right : String) -> Int {
let left_chars : Array[UInt16] = []
let right_chars : Array[UInt16] = []
for i = 0; i < left.length(); i = i + 1 {
left_chars.push(left[i])
}
for i = 0; i < right.length(); i = i + 1 {
right_chars.push(right[i])
}
let shared = if left.length() < right.length() {
left.length()
} else {
right.length()
}
for i = 0; i < shared; i = i + 1 {
if left[i] == right[i] {
left_chars[i] = 32
right_chars[i] = 32
}
let left_reverse = left.length() - 1 - i
let right_reverse = right.length() - 1 - i
if left[left_reverse] == right[right_reverse] {
left_chars[left_reverse] = 32
right_chars[right_reverse] = 32
}
}
let left_unmatched = match_rating_unmatched(left_chars)
let right_unmatched = match_rating_unmatched(right_chars)
let maximum = if left_unmatched > right_unmatched {
left_unmatched
} else {
right_unmatched
}
6 - maximum
}
///|
/// Compares two names with the Match Rating Approach decision procedure.
pub fn match_rating_compare(left : String, right : String) -> Bool {
let left_letters = normalize_ascii_letters(left)
let right_letters = normalize_ascii_letters(right)
if left_letters.length() < 2 || right_letters.length() < 2 {
return false
}
if left_letters == right_letters {
return true
}
let left_codex = match_rating_codex(left_letters)
let right_codex = match_rating_codex(right_letters)
let difference = left_codex.length() - right_codex.length()
let absolute_difference = if difference < 0 {
-difference
} else {
difference
}
if absolute_difference >= 3 {
return false
}
let minimum = match_rating_minimum(left_codex.length() + right_codex.length())
match_rating_elimination_score(left_codex, right_codex) >= minimum
}