use itertools::Itertools;
#[derive(PartialEq, Hash, Clone, Copy, Debug)]
pub enum SoundexChar {
S1,
S2,
S3,
S4,
S5,
S6,
Vowel,
HW,
Space,
}
fn encode(ch: char) -> SoundexChar {
if let Some(c) = ch.to_lowercase().next() {
match c {
'b' | 'f' | 'p' | 'v' => SoundexChar::S1,
'c' | 'g' | 'j' | 'k' | 'q' | 's' | 'x' | 'z' => SoundexChar::S2,
'd' | 't' => SoundexChar::S3,
'l' => SoundexChar::S4,
'm' | 'n' => SoundexChar::S5,
'r' => SoundexChar::S6,
'h' | 'w' => SoundexChar::HW,
' ' => SoundexChar::Space,
_ => SoundexChar::Vowel,
}
} else {
SoundexChar::Vowel
}
}
#[derive(PartialEq, Hash, Clone, Debug)]
pub struct SoundexWord {
first_char: char,
soundex_chars: Vec<SoundexChar>,
}
impl SoundexWord {
fn new(word: &str) -> SoundexWord {
let first_char = word
.chars().clone().nth(0)
.unwrap_or('_');
let soundex_chars = word
.chars()
.map(encode)
.skip(1)
.filter(|x| *x != SoundexChar::HW)
.dedup()
.filter(|x| *x != SoundexChar::Vowel)
.collect::<Vec<_>>();
SoundexWord {
first_char: first_char,
soundex_chars: soundex_chars
}
}
fn to_string(&self) -> String {
self.first_char.to_string() +
&self.soundex_chars.iter().map(|x| {
match *x {
SoundexChar::S1 => "1",
SoundexChar::S2 => "2",
SoundexChar::S3 => "3",
SoundexChar::S4 => "4",
SoundexChar::S5 => "5",
SoundexChar::S6 => "6",
SoundexChar::Space => "",
_ => "_",
}.to_owned()
}).join("")
}
}
pub fn soundex(a: &str) -> String {
let soundex_a = SoundexWord::new(a).to_string();
let mut s = String::new();
s.push_str(&soundex_a[..]);
if s.len() < 4 {
for _ in (0..(4 - s.len())).enumerate() {
s.push('0');
}
}
s.truncate(4);
s.to_uppercase()
}
pub fn compare_soundex_words(a: &str, b: &str) -> bool {
soundex(a) == soundex(b)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn soundex_1() {
assert_eq!("S550", soundex("SIMON"))
}
#[test]
fn soundex_2() {
assert_eq!("S553", soundex("Simon TESTing"))
}
#[test]
fn soundex_3() {
assert_eq!("A261", soundex("Ashcroft"))
}
#[test]
fn soundex_4() {
assert_eq!("P600", soundex("purée"))
}
#[test]
fn soundex_5() {
assert_eq!("P300", soundex("putée"))
}
#[test]
fn soundex_6() {
assert!(compare_soundex_words("putée", "putée"))
}
#[test]
fn soundex_7() {
assert!(compare_soundex_words("hey rupert", "hei robert"))
}
#[test]
fn soundex_8() {
assert!(compare_soundex_words("what's up", "wats oops"))
}
#[test]
fn soundex_9() {
assert!(compare_soundex_words("lol your stupid", "lul ur stoupid"))
}
}