#![doc = document_features::document_features!()]
#![warn(
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
trivial_numeric_casts,
unsafe_code,
unused_extern_crates,
unused_import_braces,
unused_qualifications
)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use rules_parser::*;
use serde::{Deserialize, Serialize};
pub use crate::beider_morse::{
BMError, BeiderMorse, BeiderMorseBuilder, ConfigFiles, LanguageSet, NameType, RuleType,
};
pub use crate::caverphone::{Caverphone1, Caverphone2};
pub use crate::cologne::Cologne;
pub use crate::daitch_mokotoff::{DaitchMokotoffSoundex, DaitchMokotoffSoundexBuilder};
pub use crate::double_metaphone::{DoubleMetaphone, DoubleMetaphoneResult};
pub use crate::helper::CharSequence;
pub use crate::match_rating_approach::MatchRatingApproach;
pub use crate::metaphone::Metaphone;
pub use crate::nysiis::Nysiis;
pub use crate::phonex::Phonex;
pub use crate::refined_soundex::RefinedSoundex;
pub use crate::soundex::{
Soundex, DEFAULT_US_ENGLISH_GENEALOGY_MAPPING_SOUNDEX, DEFAULT_US_ENGLISH_MAPPING_SOUNDEX,
};
mod beider_morse;
mod caverphone;
mod cologne;
mod daitch_mokotoff;
mod double_metaphone;
mod helper;
mod match_rating_approach;
mod metaphone;
mod nysiis;
mod phonex;
mod refined_soundex;
mod rules_parser;
mod soundex;
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
pub struct ParseError {
pub line_number: usize,
pub filename: Option<String>,
pub line_content: String,
pub description: String,
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{}:{} {} : {}",
self.filename
.clone()
.unwrap_or_else(|| "Unknown".to_string()),
self.line_number,
self.description,
self.line_content,
)
}
}
impl Error for ParseError {}
#[derive(Debug, Clone, PartialEq)]
pub enum PhoneticError {
ParseRuleError(ParseError),
BMError(BMError),
}
impl From<std::io::Error> for PhoneticError {
fn from(error: std::io::Error) -> Self {
Self::BMError(BMError::from(error))
}
}
impl From<regex::Error> for PhoneticError {
fn from(error: regex::Error) -> Self {
Self::BMError(BMError::from(error))
}
}
impl From<BMError> for PhoneticError {
fn from(error: BMError) -> Self {
Self::BMError(error)
}
}
impl Display for PhoneticError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::ParseRuleError(error) => write!(f, "Error parsing rule file {error}"),
Self::BMError(error) => write!(f, "Error : {error}"),
}
}
}
impl Error for PhoneticError {}
fn build_error(
line_number: usize,
filename: Option<String>,
remains: &str,
description: String,
) -> PhoneticError {
let eol = remains.find('\n');
let line_content = match eol {
None => remains,
Some(index) => &remains[..index],
}
.to_string();
PhoneticError::ParseRuleError(ParseError {
line_number,
filename,
line_content,
description,
})
}
pub trait Encoder {
fn encode(&self, s: &str) -> String;
fn is_encoded_equals(&self, first: &str, second: &str) -> bool {
let f = self.encode(first);
let s = self.encode(second);
f == s
}
}
trait SoundexUtils {
fn soundex_clean(value: &str) -> String {
value
.chars()
.filter(|c| c.is_alphabetic())
.map(|c| c.to_uppercase().collect::<String>())
.collect()
}
}
pub trait SoundexCommons: Encoder {
fn difference(&self, value1: &str, value2: &str) -> usize {
let value1 = self.encode(value1);
let value2 = self.encode(value2);
if value1.is_empty() || value2.is_empty() {
return 0;
}
let mut result: usize = 0;
for (ch1, ch2) in value1.chars().zip(value2.chars()) {
if ch1 == ch2 {
result += 1;
}
}
result
}
}