owoify_rs 1.0.0

This Rust port of mohan-cao's owoify-js is released under MIT license, which is also the same license of owoify-js. This simple library will turn any string into nonsensical babyspeak similar to what LeafySweet's infamous Chrome extension did.
Documentation
#![allow(clippy::trivial_regex)]
use crate::structures::Word;
use rand::prelude::*;
use regex::Regex;

lazy_static! {
    static ref O_TO_OWO: Regex = Regex::new(r"o").expect("Failed to build regular expression.");
    static ref EW_TO_UWU: Regex = Regex::new(r"ew").expect("Failed to build regular expression.");
    static ref HEY_TO_HAY: Regex = Regex::new(r"([Hh])ey").expect("Failed to build regular expression.");
    static ref DEAD_TO_DED_UPPER: Regex = Regex::new(r"Dead").expect("Failed to build regular expression.");
    static ref DEAD_TO_DED_LOWER: Regex = Regex::new(r"dead").expect("Failed to build regular expression.");
    static ref N_VOWEL_T_TO_ND: Regex = Regex::new(r"n[aeiou]*t").expect("Failed to build regular expression.");
    static ref READ_TO_WEAD_UPPER: Regex = Regex::new(r"Read").expect("Failed to build regular expression.");
    static ref READ_TO_WEAD_LOWER: Regex = Regex::new(r"read").expect("Failed to build regular expression.");
    static ref BRACKETS_TO_STARTRAILS_FORE: Regex = Regex::new(r"[({<]").expect("Failed to build regular expression.");
    static ref BRACKETS_TO_STARTRAILS_REAR: Regex = Regex::new(r"[)}>]").expect("Failed to build regular expression.");
    //static ref PERIOD_COMMA_EXCLAMATION_SEMICOLON_TO_KAOMOJIS_FIRST: Regex = Regex::new(r"[.,](?![0-9])").expect("Failed to build regular expression.");
    static ref PERIOD_COMMA_EXCLAMATION_SEMICOLON_TO_KAOMOJIS_FIRST: Regex = Regex::new(r"[.,]").expect("Failed to build regular expression.");
    static ref PERIOD_COMMA_EXCLAMATION_SEMICOLON_TO_KAOMOJIS_SECOND: Regex = Regex::new(r"[!;]+").expect("Failed to build regular expression.");
    static ref THAT_TO_DAT_UPPER: Regex = Regex::new(r"That").expect("Failed to build regular expression.");
    static ref THAT_TO_DAT_LOWER: Regex = Regex::new(r"that").expect("Failed to build regular expression.");
    //static ref TH_TO_F_UPPER: Regex = Regex::new(r"TH(?!E)").expect("Failed to build regular expression.");
    static ref TH_TO_F_UPPER: Regex = Regex::new(r"TH").expect("Failed to build regular expression.");
    //static ref TH_TO_F_LOWER: Regex = Regex::new(r"[Tt]h(?![Ee])").expect("Failed to build regular expression.");
    static ref TH_TO_F_LOWER: Regex = Regex::new(r"[Tt]h").expect("Failed to build regular expression.");
    static ref LE_TO_WAL: Regex = Regex::new(r"le$").expect("Failed to build regular expression.");
    static ref VE_TO_WE_UPPER: Regex = Regex::new(r"Ve").expect("Failed to build regular expression.");
    static ref VE_TO_WE_LOWER: Regex = Regex::new(r"ve").expect("Failed to build regular expression.");
    static ref RY_TO_WWY: Regex = Regex::new(r"ry").expect("Failed to build regular expression.");
    static ref RORL_TO_W_UPPER: Regex = Regex::new(r"(?:R|L)").expect("Failed to build regular expression.");
    static ref RORL_TO_W_LOWER: Regex = Regex::new(r"(?:r|l)").expect("Failed to build regular expression.");
    static ref LL_TO_WW: Regex = Regex::new(r"ll").expect("Failed to build regular expression.");
    static ref VOWEL_OR_R_EXCEPT_O_L_TO_WL_UPPER: Regex = Regex::new(r"[AEIUR]([lL])$").expect("Failed to build regular expression.");
    static ref VOWEL_OR_R_EXCEPT_O_L_TO_WL_LOWER: Regex = Regex::new(r"[aeiur]l$").expect("Failed to build regular expression.");
    static ref OLD_TO_OWLD_UPPER: Regex = Regex::new(r"OLD").expect("Failed to build regular expression.");
    static ref OLD_TO_OWLD_LOWER: Regex = Regex::new(r"([Oo])ld").expect("Failed to build regular expression.");
    static ref OL_TO_OWL_UPPER: Regex = Regex::new(r"OL").expect("Failed to build regular expression.");
    static ref OL_TO_OWL_LOWER: Regex = Regex::new(r"([Oo])l").expect("Failed to build regular expression.");
    static ref LORR_O_TO_WO_UPPER: Regex = Regex::new(r"[LR]([oO])").expect("Failed to build regular expression.");
    static ref LORR_O_TO_WO_LOWER: Regex = Regex::new(r"[lr]o").expect("Failed to build regular expression.");
    static ref SPECIFIC_CONSONANTS_O_TO_LETTER_AND_WO_UPPER: Regex = Regex::new(r"([BCDFGHJKMNPQSTXYZ])([oO])").expect("Failed to build regular expression.");
    static ref SPECIFIC_CONSONANTS_O_TO_LETTER_AND_WO_LOWER: Regex = Regex::new(r"([bcdfghjkmnpqstxyz])o").expect("Failed to build regular expression.");
    static ref VORW_LE_TO_WAL: Regex = Regex::new(r"[vw]le").expect("Failed to build regular expression.");
    static ref FI_TO_FWI_UPPER: Regex = Regex::new(r"FI").expect("Failed to build regular expression.");
    static ref FI_TO_FWI_LOWER: Regex = Regex::new(r"([Ff])i").expect("Failed to build regular expression.");
    static ref VER_TO_WER: Regex = Regex::new(r"([Vv])er").expect("Failed to build regular expression.");
    static ref POI_TO_PWOI: Regex = Regex::new(r"([Pp])oi").expect("Failed to build regular expression.");
    static ref SPECIFIC_CONSONANTS_LE_TO_LETTER_AND_WAL: Regex = Regex::new(r"([DdFfGgHhJjPpQqRrSsTtXxYyZz])le$").expect("Failed to build regular expression.");
    static ref CONSONANT_R_TO_CONSONANT_W: Regex = Regex::new(r"([BbCcDdFfGgKkPpQqSsTtWwXxZz])r").expect("Failed to build regular expression.");
    static ref LY_TO_WY_UPPER: Regex = Regex::new(r"Ly").expect("Failed to build regular expression.");
    static ref LY_TO_WY_LOWER: Regex = Regex::new(r"ly").expect("Failed to build regular expression.");
    static ref PLE_TO_PWE: Regex = Regex::new(r"([Pp])le").expect("Failed to build regular expression.");
    static ref NR_TO_NW_UPPER: Regex = Regex::new(r"NR").expect("Failed to build regular expression.");
    static ref NR_TO_NW_LOWER: Regex = Regex::new(r"nr").expect("Failed to build regular expression.");
    static ref FUC_TO_FWUC: Regex = Regex::new(r"([Ff])uc").expect("Failed to build regular expression.");
    static ref MOM_TO_MWOM: Regex = Regex::new(r"([Mm])om").expect("Failed to build regular expression.");
    static ref ME_TO_MWE: Regex = Regex::new(r"([Mm])e").expect("Failed to build regular expression.");
    static ref N_VOWEL_TO_NY_FIRST: Regex = Regex::new(r"n([aeiou])").expect("Failed to build regular expression.");
    static ref N_VOWEL_TO_NY_SECOND: Regex = Regex::new(r"N([aeiou])").expect("Failed to build regular expression.");
    static ref N_VOWEL_TO_NY_THIRD: Regex = Regex::new(r"N([AEIOU])").expect("Failed to build regular expression.");
    static ref OVE_TO_UV_UPPER: Regex = Regex::new(r"OVE").expect("Failed to build regular expression.");
    static ref OVE_TO_UV_LOWER: Regex = Regex::new(r"ove").expect("Failed to build regular expression.");
    static ref HAHA_TO_HEHE_XD: Regex = Regex::new(r"\b(ha|hah|heh|hehe)+\b").expect("Failed to build regular expression.");
    static ref THE_TO_TEH: Regex = Regex::new(r"\b([Tt])he\b").expect("Failed to build regular expression.");
    static ref YOU_TO_U_UPPER: Regex = Regex::new(r"\bYou\b").expect("Failed to build regular expression.");
    static ref YOU_TO_U_LOWER: Regex = Regex::new(r"\byou\b").expect("Failed to build regular expression.");
    static ref TIME_TO_TIM: Regex = Regex::new(r"\b([Tt])ime\b").expect("Failed to build regular expression.");
    static ref OVER_TO_OWOR: Regex = Regex::new(r"([Oo])ver").expect("Failed to build regular expression.");
    static ref WORSE_TO_WOSE: Regex = Regex::new(r"([Ww])orse").expect("Failed to build regular expression.");
}

pub(crate) const FACES: [&str; 29] = [
    "(・`ω´・)",
    ";;w;;",
    "owo",
    "UwU",
    ">w<",
    "^w^",
    "(* ^ ω ^)",
    "(⌒ω⌒)",
    "ヽ(*・ω・)ノ",
    "(o´∀`o)",
    "(o・ω・o)",
    "\(^▽^)/",
    "(*^ω^)",
    "(◕‿◕✿)",
    "(◕ᴥ◕)",
    "ʕ•ᴥ•ʔ",
    "ʕ→ᴥ←ʔ",
    "(*^.^*)",
    "(。♥‿♥。)",
    "OwO",
    "uwu",
    "uvu",
    "UvU",
    "(* ̄з ̄)",
    "(つ✧ω✧)つ",
    "(/ =ω=)/",
    "(╯°□°)╯︵ ┻━┻",
    "┬─┬ ノ( ゜-゜ノ)",
    "¯\\_(ツ)_/¯",
];

pub(crate) fn map_o_to_owo(input: Word) -> Word {
    let replacement = if thread_rng().gen_range(0..2) > 0 {
        "owo"
    } else {
        "o"
    };
    let reg: &Regex = &*O_TO_OWO;
    input.replace(reg, replacement, false)
}

pub(crate) fn map_ew_to_uwu(input: Word) -> Word {
    let reg: &Regex = &*EW_TO_UWU;
    input.replace(reg, "uwu", false)
}

pub(crate) fn map_hey_to_hay(input: Word) -> Word {
    let reg: &Regex = &*HEY_TO_HAY;
    input.replace(reg, "${1}ay", false)
}

pub(crate) fn map_dead_to_ded(input: Word) -> Word {
    let reg_upper: &Regex = &*DEAD_TO_DED_UPPER;
    let reg_lower: &Regex = &*DEAD_TO_DED_LOWER;
    input
        .replace(reg_upper, "Ded", false)
        .replace(reg_lower, "ded", false)
}

pub(crate) fn map_n_vowel_t_to_nd(input: Word) -> Word {
    let reg: &Regex = &*N_VOWEL_T_TO_ND;
    input.replace(reg, "nd", false)
}

pub(crate) fn map_read_to_wead(input: Word) -> Word {
    let reg_upper: &Regex = &*READ_TO_WEAD_UPPER;
    let reg_lower: &Regex = &*READ_TO_WEAD_LOWER;
    input
        .replace(reg_upper, "Wead", false)
        .replace(reg_lower, "wead", false)
}

pub(crate) fn map_brackets_to_star_trails(input: Word) -> Word {
    let reg_fore: &Regex = &*BRACKETS_TO_STARTRAILS_FORE;
    let reg_rear: &Regex = &*BRACKETS_TO_STARTRAILS_REAR;
    input.replace(reg_fore, "。・:*:・゚★,。・:*:・゚☆", false).replace(
        reg_rear,
        "☆゚・:*:・。,★゚・:*:・。",
        false,
    )
}

pub(crate) fn map_period_comma_exclamation_semicolon_to_kaomojis(input: Word) -> Word {
    let reg_first: &Regex = &*PERIOD_COMMA_EXCLAMATION_SEMICOLON_TO_KAOMOJIS_FIRST;
    let reg_second: &Regex = &*PERIOD_COMMA_EXCLAMATION_SEMICOLON_TO_KAOMOJIS_SECOND;
    input
        .replace_with_func_single(
            reg_first,
            || {
                let mut rng = thread_rng();
                " ".to_string()
                    + FACES
                        .choose(&mut rng)
                        .copied()
                        .expect("Failed to get a random face.")
            },
            false,
        )
        .replace_with_func_single(
            reg_second,
            || {
                let mut rng = thread_rng();
                " ".to_string()
                    + FACES
                        .choose(&mut rng)
                        .copied()
                        .expect("Failed to get a random face.")
            },
            false,
        )
}

pub(crate) fn map_that_to_dat(input: Word) -> Word {
    let reg_upper: &Regex = &*THAT_TO_DAT_UPPER;
    let reg_lower: &Regex = &*THAT_TO_DAT_LOWER;
    input
        .replace(reg_lower, "dat", false)
        .replace(reg_upper, "Dat", false)
}

pub(crate) fn map_th_to_f(input: Word) -> Word {
    let reg_upper: &Regex = &*TH_TO_F_UPPER;
    let reg_lower: &Regex = &*TH_TO_F_LOWER;
    input
        .replace(reg_lower, "f", false)
        .replace(reg_upper, "F", false)
}

pub(crate) fn map_le_to_wal(input: Word) -> Word {
    let reg: &Regex = &*LE_TO_WAL;
    input.replace(reg, "wal", false)
}

pub(crate) fn map_ve_to_we(input: Word) -> Word {
    let reg_upper: &Regex = &*VE_TO_WE_UPPER;
    let reg_lower: &Regex = &*VE_TO_WE_LOWER;
    input
        .replace(reg_lower, "we", false)
        .replace(reg_upper, "We", false)
}

pub(crate) fn map_ry_to_wwy(input: Word) -> Word {
    let reg: &Regex = &*RY_TO_WWY;
    input.replace(reg, "wwy", false)
}

pub(crate) fn map_r_or_l_to_w(input: Word) -> Word {
    let reg_upper: &Regex = &*RORL_TO_W_UPPER;
    let reg_lower: &Regex = &*RORL_TO_W_LOWER;
    input
        .replace(reg_lower, "w", false)
        .replace(reg_upper, "W", false)
}

pub(crate) fn map_ll_to_ww(input: Word) -> Word {
    let reg: &Regex = &*LL_TO_WW;
    input.replace(reg, "ww", false)
}

pub(crate) fn map_vowel_or_r_except_o_l_to_wl(input: Word) -> Word {
    let reg_upper: &Regex = &*VOWEL_OR_R_EXCEPT_O_L_TO_WL_UPPER;
    let reg_lower: &Regex = &*VOWEL_OR_R_EXCEPT_O_L_TO_WL_LOWER;
    input
        .replace(reg_lower, "wl", false)
        .replace(reg_upper, "W${1}", false)
}

pub(crate) fn map_old_to_owld(input: Word) -> Word {
    let reg_upper: &Regex = &*OLD_TO_OWLD_UPPER;
    let reg_lower: &Regex = &*OLD_TO_OWLD_LOWER;
    input
        .replace(reg_lower, "${1}wld", false)
        .replace(reg_upper, "OWLD", false)
}

pub(crate) fn map_ol_to_owl(input: Word) -> Word {
    let reg_upper: &Regex = &*OL_TO_OWL_UPPER;
    let reg_lower: &Regex = &*OL_TO_OWL_LOWER;
    input
        .replace(reg_lower, "${1}wl", false)
        .replace(reg_upper, "OWL", false)
}

pub(crate) fn map_l_or_r_o_to_wo(input: Word) -> Word {
    let reg_upper: &Regex = &*LORR_O_TO_WO_UPPER;
    let reg_lower: &Regex = &*LORR_O_TO_WO_LOWER;
    input
        .replace(reg_lower, "wo", false)
        .replace(reg_upper, "W${1}", false)
}

pub(crate) fn map_specific_consonants_o_to_letter_and_wo(input: Word) -> Word {
    let reg_upper: &Regex = &*SPECIFIC_CONSONANTS_O_TO_LETTER_AND_WO_UPPER;
    let reg_lower: &Regex = &*SPECIFIC_CONSONANTS_O_TO_LETTER_AND_WO_LOWER;
    input
        .replace(reg_lower, "${1}wo", false)
        .replace_with_func_multiple(
            reg_upper,
            |s1, s2| {
                let mut msg = s1.to_string();
                msg += if s2.to_uppercase() == *s2 { "W" } else { "w" };
                msg += s2;
                msg
            },
            false,
        )
}

pub(crate) fn map_v_or_w_le_to_wal(input: Word) -> Word {
    let reg: &Regex = &*LE_TO_WAL;
    input.replace(reg, "wal", false)
}

pub(crate) fn map_fi_to_fwi(input: Word) -> Word {
    let reg_upper: &Regex = &*FI_TO_FWI_UPPER;
    let reg_lower: &Regex = &*FI_TO_FWI_LOWER;
    input
        .replace(reg_lower, "${1}wi", false)
        .replace(reg_upper, "FWI", false)
}

pub(crate) fn map_ver_to_wer(input: Word) -> Word {
    let reg: &Regex = &*VER_TO_WER;
    input.replace(reg, "wer", false)
}

pub(crate) fn map_poi_to_pwoi(input: Word) -> Word {
    let reg: &Regex = &*POI_TO_PWOI;
    input.replace(reg, "${1}woi", false)
}

pub(crate) fn map_specific_consonants_le_to_letter_and_wal(input: Word) -> Word {
    let reg: &Regex = &*SPECIFIC_CONSONANTS_LE_TO_LETTER_AND_WAL;
    input.replace(reg, "${1}wal", false)
}

pub(crate) fn map_consonant_r_to_consonant_w(input: Word) -> Word {
    let reg: &Regex = &*CONSONANT_R_TO_CONSONANT_W;
    input.replace(reg, "${1}w", false)
}

pub(crate) fn map_ly_to_wy(input: Word) -> Word {
    let reg_upper: &Regex = &*LY_TO_WY_UPPER;
    let reg_lower: &Regex = &*LY_TO_WY_LOWER;
    input
        .replace(reg_lower, "wy", false)
        .replace(reg_upper, "Wy", false)
}

pub(crate) fn map_ple_to_pwe(input: Word) -> Word {
    let reg: &Regex = &*PLE_TO_PWE;
    input.replace(reg, "${1}we", false)
}

pub(crate) fn map_nr_to_nw(input: Word) -> Word {
    let reg_upper: &Regex = &*NR_TO_NW_UPPER;
    let reg_lower: &Regex = &*NR_TO_NW_LOWER;
    input
        .replace(reg_lower, "nw", false)
        .replace(reg_upper, "NW", false)
}

pub(crate) fn map_fuc_to_fwuc(input: Word) -> Word {
    let reg: &Regex = &*FUC_TO_FWUC;
    input.replace(reg, "${1}wuc", false)
}

pub(crate) fn map_mom_to_mwom(input: Word) -> Word {
    let reg: &Regex = &*MOM_TO_MWOM;
    input.replace(reg, "${1}wom", false)
}

pub(crate) fn map_me_to_mwe(input: Word) -> Word {
    let reg: &Regex = &*ME_TO_MWE;
    input.replace(reg, "${1}we", false)
}

pub(crate) fn map_n_vowel_to_ny(input: Word) -> Word {
    let reg_first: &Regex = &*N_VOWEL_TO_NY_FIRST;
    let reg_second: &Regex = &*N_VOWEL_TO_NY_SECOND;
    let reg_third: &Regex = &*N_VOWEL_TO_NY_THIRD;
    input
        .replace(reg_first, "ny${1}", false)
        .replace(reg_second, "Ny${1}", false)
        .replace(reg_third, "NY${1}", false)
}

pub(crate) fn map_ove_to_uv(input: Word) -> Word {
    let reg_upper: &Regex = &*OVE_TO_UV_UPPER;
    let reg_lower: &Regex = &*OVE_TO_UV_LOWER;
    input
        .replace(reg_lower, "uv", false)
        .replace(reg_upper, "UV", false)
}

pub(crate) fn map_haha_to_hehe_xd(input: Word) -> Word {
    let reg: &Regex = &*HAHA_TO_HEHE_XD;
    input.replace(reg, "hehe xD", false)
}

pub(crate) fn map_the_to_teh(input: Word) -> Word {
    let reg: &Regex = &*THE_TO_TEH;
    input.replace(reg, "${1}eh", false)
}

pub(crate) fn map_you_to_u(input: Word) -> Word {
    let reg_upper: &Regex = &*YOU_TO_U_UPPER;
    let reg_lower: &Regex = &*YOU_TO_U_LOWER;
    input
        .replace(reg_upper, "U", false)
        .replace(reg_lower, "u", false)
}

pub(crate) fn map_time_to_tim(input: Word) -> Word {
    let reg: &Regex = &*TIME_TO_TIM;
    input.replace(reg, "${1}im", false)
}

pub(crate) fn map_over_to_owor(input: Word) -> Word {
    let reg: &Regex = &*OVER_TO_OWOR;
    input.replace(reg, "${1}wor", false)
}

pub(crate) fn map_worse_to_wose(input: Word) -> Word {
    let reg: &Regex = &*WORSE_TO_WOSE;
    input.replace(reg, "${1}ose", false)
}