use crate::data::{
EXCEPTIONS_FINAL_ER, EXCEPTIONS_FINAL_TIEN, MOTS_ENT, MOTS_S_FINAL, MOTS_T_FINAL,
POSSIBLES_AVOIR, POSSIBLES_NC_AI_FINAL, VERBES_ENTER, VERBES_IER, VERBES_MER,
};
fn no_accent(s: &str) -> String {
s.chars()
.map(|c| match c {
'à' | 'ä' | 'â' => 'a',
'é' | 'è' | 'ê' | 'ë' => 'e',
'î' | 'ï' => 'i',
'ô' | 'ö' => 'o',
'û' | 'ù' => 'u',
'ç' => 'c',
'œ' => 'e',
other => other.to_lowercase().next().unwrap_or(other),
})
.collect()
}
fn as_string(word: &[char]) -> String {
word.iter().collect()
}
fn strip_elision(s: &str) -> String {
let chars: Vec<char> = s.chars().collect();
if chars.len() > 1 && chars[1] == '@' {
chars[2..].iter().collect()
} else {
s.to_string()
}
}
fn ends_with(word: &[char], suffix: &str) -> bool {
let sc: Vec<char> = suffix.chars().collect();
if word.len() < sc.len() {
return false;
}
word[word.len() - sc.len()..] == sc[..]
}
fn strip_final_s(s: &str) -> String {
let chars: Vec<char> = s.chars().collect();
if chars.last().copied() == Some('s') {
chars[..chars.len() - 1].iter().collect()
} else {
s.to_string()
}
}
pub fn regle_ient(word: &[char], pos_mot: usize) -> bool {
if word.len() < 5 {
return false;
}
let last_five = &word[word.len() - 5..];
let consonnes = "bcçdfghjklnmpqrstvwxz";
if !consonnes.contains(last_five[0])
|| last_five[1] != 'i'
|| last_five[2] != 'e'
|| last_five[3] != 'n'
|| last_five[4] != 't'
{
return false;
}
if pos_mot < word.len() - 4 {
return false;
}
let mut pseudo: String = word[..word.len() - 2].iter().collect();
pseudo.push('r');
if VERBES_IER.binary_search(&pseudo.as_str()).is_ok() {
return true;
}
let mut pseudo_na = no_accent(&pseudo);
if pseudo_na.chars().nth(1) == Some('@') {
pseudo_na = pseudo_na.chars().skip(2).collect();
}
VERBES_IER.binary_search(&pseudo_na.as_str()).is_ok()
}
pub fn regle_mots_ent(word: &[char], pos_mot: usize) -> bool {
let mot_str = as_string(word);
let len = word.len();
if (len == 4 || len == 5)
&& "bcdfghjklmnpqrstvwxz".contains(word[0])
&& word[1] == 'e'
&& word[2] == 'n'
&& word[3] == 't'
&& (len == 4 || word[4] == 's')
{
return true;
}
let comparateur = if mot_str.ends_with('s') {
&mot_str[..mot_str.len() - 1]
} else {
&mot_str[..]
};
let comp_len = comparateur.chars().count();
if pos_mot + 2 < comp_len {
return false;
}
let comparateur = strip_elision(comparateur);
if MOTS_ENT.binary_search(&comparateur.as_str()).is_ok() {
return true;
}
let pseudo_verbe = format!("{}er", comparateur);
VERBES_ENTER.binary_search(&pseudo_verbe.as_str()).is_ok()
}
pub fn regle_ment(word: &[char], pos_mot: usize) -> bool {
if !ends_with(word, "ment") {
return false;
}
if pos_mot < word.len() - 3 {
return false;
}
let base: String = word[..word.len() - 2].iter().collect();
let mut pseudo = no_accent(&format!("{}r", base));
if pseudo.chars().nth(1) == Some('@') {
pseudo = pseudo.chars().skip(2).collect();
}
if VERBES_MER.binary_search(&pseudo.as_str()).is_ok() {
return false;
}
if word.len() > 6 && ends_with(word, "dorment") {
return false;
}
true
}
pub fn regle_verbe_mer(word: &[char], pos_mot: usize) -> bool {
if !ends_with(word, "ment") {
return false;
}
if pos_mot < word.len() - 3 {
return false;
}
!regle_ment(word, pos_mot)
}
pub fn regle_er(word: &[char], _pos_mot: usize) -> bool {
let mot = as_string(word);
let m_sing = strip_final_s(&mot);
let m_sing = strip_elision(&m_sing);
if !m_sing.ends_with("er") {
return false;
}
EXCEPTIONS_FINAL_ER.binary_search(&m_sing.as_str()).is_ok()
}
pub fn regle_nc_ai_final(word: &[char], pos_mot: usize) -> bool {
let mot = as_string(word);
let m_seul = strip_elision(&mot);
if POSSIBLES_NC_AI_FINAL
.binary_search(&m_seul.as_str())
.is_ok()
{
return pos_mot == word.len() - 1;
}
false
}
pub fn regle_avoir(word: &[char], pos_mot: usize) -> bool {
let mot = as_string(word);
if POSSIBLES_AVOIR.binary_search(&mot.as_str()).is_ok() {
return pos_mot < 2;
}
false
}
pub fn regle_s_final(word: &[char], _pos_mot: usize) -> bool {
let mot = as_string(word);
let m_seul = strip_elision(&mot);
MOTS_S_FINAL.binary_search(&m_seul.as_str()).is_ok()
}
pub fn regle_t_final(word: &[char], _pos_mot: usize) -> bool {
let mot = as_string(word);
let m_sing = strip_final_s(&mot);
let m_sing = strip_elision(&m_sing);
MOTS_T_FINAL.binary_search(&m_sing.as_str()).is_ok()
}
pub fn regle_tien(word: &[char], pos_mot: usize) -> bool {
let mot = as_string(word);
let m_sing = strip_final_s(&mot);
let chars: Vec<char> = m_sing.chars().collect();
if chars.len() < 4 {
return false;
}
let last4: String = chars[chars.len() - 4..].iter().collect();
if last4 != "tien" {
return false;
}
if pos_mot < chars.len() - 4 {
return false;
}
EXCEPTIONS_FINAL_TIEN
.binary_search(&m_sing.as_str())
.is_ok()
}
#[cfg(test)]
mod tests {
use super::*;
fn chars(s: &str) -> Vec<char> {
s.chars().collect()
}
#[test]
fn test_no_accent() {
assert_eq!(no_accent("élève"), "eleve");
assert_eq!(no_accent("garçon"), "garcon");
assert_eq!(no_accent("œuf"), "euf");
}
#[test]
fn test_ends_with() {
let w = chars("parlent");
assert!(ends_with(&w, "ent"));
assert!(!ends_with(&w, "ant"));
}
#[test]
fn regle_mots_ent_sur_prudent() {
let w = chars("prudent");
assert!(regle_mots_ent(&w, 5));
}
#[test]
fn regle_mots_ent_sur_parlent() {
let w = chars("parlent");
assert!(!regle_mots_ent(&w, 5));
}
}