mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 02:00:46 +00:00
ban slurs with latin characters and upper case
This commit is contained in:
1 parent
c25639baa4
commit
e56ac834ee
5 files changed
+166
-2
No files matched your search
Generated
+1
@@ -4548,6 +4548,7 @@ dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -22,3 +22,4 @@ anyhow = "1.0.40"
|
||||
log = "0.4.14"
|
||||
once_cell = "1.9.0"
|
||||
regex = "1.5.4"
|
||||
unicode-segmentation = "1.7.1"
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::BANNED_SLURS;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashSet;
|
||||
use crate::latin_alphabet::latin_to_ascii;
|
||||
|
||||
static BANNED_SLURS_SET : Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
BANNED_SLURS.lines()
|
||||
@@ -11,12 +12,12 @@ static BANNED_SLURS_SET : Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
pub fn contains_slurs(unparsed_text: &str) -> bool {
|
||||
for wordlike in unparsed_text.split_ascii_whitespace() {
|
||||
let simplified = latin_to_ascii(unparsed_text).to_lowercase();
|
||||
for wordlike in simplified.split_ascii_whitespace() {
|
||||
if BANNED_SLURS_SET.contains(wordlike) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
@@ -37,4 +38,30 @@ mod tests {
|
||||
assert_eq!(contains_slurs("a sentence containing fag is banned"), true);
|
||||
assert_eq!(contains_slurs("a\nsentence\ncontaining fags\nis banned"), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_with_mixed_case_slurs_fails() {
|
||||
assert_eq!(contains_slurs("FAG"), true);
|
||||
assert_eq!(contains_slurs("FaG"), true);
|
||||
assert_eq!(contains_slurs("fAg"), true);
|
||||
assert_eq!(contains_slurs("A SENTENCE CONTAINING FAG IS BANNED"), true);
|
||||
assert_eq!(contains_slurs("a\nsentence\ncontaining FAGS\nis banned"), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_with_latin_obfuscated_slurs_fails() {
|
||||
assert_eq!(contains_slurs("FÀG"), true);
|
||||
assert_eq!(contains_slurs("FÁG"), true);
|
||||
assert_eq!(contains_slurs("FÂG"), true);
|
||||
assert_eq!(contains_slurs("FÃG"), true);
|
||||
assert_eq!(contains_slurs("FÄG"), true);
|
||||
assert_eq!(contains_slurs("FÅG"), true);
|
||||
|
||||
assert_eq!(contains_slurs("fàg"), true);
|
||||
assert_eq!(contains_slurs("fág"), true);
|
||||
assert_eq!(contains_slurs("fâg"), true);
|
||||
assert_eq!(contains_slurs("fãg"), true);
|
||||
assert_eq!(contains_slurs("fäg"), true);
|
||||
assert_eq!(contains_slurs("fåg"), true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
// http://www.geocities.ws/click2speak/unicode/chars_es.html
|
||||
pub static LATIN_CHARACTER_MAP : Lazy<HashMap<String, String>> = Lazy::new(|| {
|
||||
let mut map = HashMap::new();
|
||||
// Latin characters with accent (A)
|
||||
map.insert("\u{C0}".to_string(), "A".to_string()); // Latin capital letter a with grave
|
||||
map.insert("\u{C1}".to_string(), "A".to_string()); // Latin capital letter a with acute
|
||||
map.insert("\u{C2}".to_string(), "A".to_string()); // Latin capital letter a with circumflex
|
||||
map.insert("\u{C3}".to_string(), "A".to_string()); // Latin capital letter a with tilde
|
||||
map.insert("\u{C4}".to_string(), "A".to_string()); // Latin capital letter a diaeresis
|
||||
map.insert("\u{C5}".to_string(), "A".to_string()); // Latin capital letter a with ring above
|
||||
// Latin characters with accent (AE)
|
||||
map.insert("\u{C6}".to_string(), "AE".to_string()); // Latin capital letter ae
|
||||
// Latin characters with accent (C)
|
||||
map.insert("\u{C7}".to_string(), "C".to_string()); // Latin capital letter c with cedilla
|
||||
// Latin characters with accent (E)
|
||||
map.insert("\u{C8}".to_string(), "E".to_string()); // Latin capital letter e with grave
|
||||
map.insert("\u{C9}".to_string(), "E".to_string()); // Latin capital letter e with acute
|
||||
map.insert("\u{CA}".to_string(), "E".to_string()); // Latin capital letter e with circumflex
|
||||
map.insert("\u{CB}".to_string(), "E".to_string()); // Latin capital letter e with diaeresis
|
||||
// Latin characters with accent (I)
|
||||
map.insert("\u{CC}".to_string(), "I".to_string()); // Latin capital letter i with grave
|
||||
map.insert("\u{CD}".to_string(), "I".to_string()); // Latin capital letter i with acute
|
||||
map.insert("\u{CE}".to_string(), "I".to_string()); // Latin capital letter i with circumflex
|
||||
map.insert("\u{CF}".to_string(), "I".to_string()); // Latin capital letter i with diaeresis
|
||||
// Latin characters with accent (ETH)
|
||||
// map.insert("\u{D0}".to_string(), "D".to_string()); // Latin capital letter eth
|
||||
// Latin characters with accent (N)
|
||||
map.insert("\u{D1}".to_string(), "N".to_string()); // Latin capital letter n with tilde
|
||||
// Latin characters with accent (O)
|
||||
map.insert("\u{D2}".to_string(), "O".to_string()); // Latin capital letter o with grave
|
||||
map.insert("\u{D3}".to_string(), "O".to_string()); // Latin capital letter o with acute
|
||||
map.insert("\u{D4}".to_string(), "O".to_string()); // Latin capital letter o with circumflex
|
||||
map.insert("\u{D5}".to_string(), "O".to_string()); // Latin capital letter o with tilde
|
||||
map.insert("\u{D6}".to_string(), "O".to_string()); // Latin capital letter o with diaeresis
|
||||
map.insert("\u{D8}".to_string(), "O".to_string()); // Latin capital letter o with stroke (NB: Skips D7)
|
||||
// Latin characters with accent (U)
|
||||
map.insert("\u{D9}".to_string(), "U".to_string()); // Latin capital letter u with grave
|
||||
map.insert("\u{DA}".to_string(), "U".to_string()); // Latin capital letter u with acute
|
||||
map.insert("\u{DB}".to_string(), "U".to_string()); // Latin capital letter u with circumflex
|
||||
map.insert("\u{DC}".to_string(), "U".to_string()); // Latin capital letter u with diaeresis
|
||||
// Latin characters with accent (Y)
|
||||
map.insert("\u{DD}".to_string(), "Y".to_string()); // Latin capital letter y with acute
|
||||
// Latin characters with accent (THORN)
|
||||
// map.insert("\u{DE}".to_string(), "P".to_string()); // Latin capital letter thorn
|
||||
// Latin characters with accent (SHARP S)
|
||||
// map.insert("\u{DF}".to_string(), "B".to_string()); // Latin capital letter sharp s
|
||||
// Latin characters with accent (a)
|
||||
map.insert("\u{E0}".to_string(), "a".to_string()); // Latin small letter a with grave
|
||||
map.insert("\u{E1}".to_string(), "a".to_string()); // Latin small letter a with acute
|
||||
map.insert("\u{E2}".to_string(), "a".to_string()); // Latin small letter a with circumflex
|
||||
map.insert("\u{E3}".to_string(), "a".to_string()); // Latin small letter a with tilde
|
||||
map.insert("\u{E4}".to_string(), "a".to_string()); // Latin small letter a with diaeresis
|
||||
map.insert("\u{E5}".to_string(), "a".to_string()); // Latin small letter a with ring above
|
||||
// Latin characters with accent (ae)
|
||||
map.insert("\u{E6}".to_string(), "ae".to_string()); // Latin small letter ae
|
||||
// Latin characters with accent (c)
|
||||
map.insert("\u{E7}".to_string(), "c".to_string()); // Latin small letter c with cedilla
|
||||
// Latin characters with accent (e)
|
||||
map.insert("\u{E8}".to_string(), "e".to_string()); // Latin small letter e with grave
|
||||
map.insert("\u{E9}".to_string(), "e".to_string()); // Latin small letter e with acute
|
||||
map.insert("\u{EA}".to_string(), "e".to_string()); // Latin small letter e with circumflex
|
||||
map.insert("\u{EB}".to_string(), "e".to_string()); // Latin small letter e with diaeresis
|
||||
// Latin characters with accent (i)
|
||||
map.insert("\u{EC}".to_string(), "i".to_string()); // Latin small letter i with grave
|
||||
map.insert("\u{ED}".to_string(), "i".to_string()); // Latin small letter i with acute
|
||||
map.insert("\u{EE}".to_string(), "i".to_string()); // Latin small letter i with circumflex
|
||||
map.insert("\u{EF}".to_string(), "i".to_string()); // Latin small letter i with diaeresis
|
||||
// Latin characters with accent (eth)
|
||||
// map.insert("\u{F0}".to_string(), "d".to_string()); // Latin small letter eith
|
||||
// Spanish special characters
|
||||
map.insert("\u{F1}".to_string(), "n".to_string()); // Lower n tilde
|
||||
map.insert("\u{AA}".to_string(), "a".to_string()); // Feminine ordinal
|
||||
map.insert("\u{BA}".to_string(), "o".to_string()); // Masculine ordinal
|
||||
// Misc characters that frequently occur
|
||||
map.insert("\u{00F3}".to_string(), "o".to_string()); // Latin Small Letter O with Acute
|
||||
map.insert("\u{0131}".to_string(), "i".to_string()); // Latin Small Letter Dotless I
|
||||
map.insert("\u{00FC}".to_string(), "u".to_string()); // Latin Small Letter U with Diaeresis
|
||||
map.insert("\u{015F}".to_string(), "s".to_string()); // Latin Small Letter S with Cedilla
|
||||
map.insert("\u{00F6}".to_string(), "o".to_string()); // Latin Small Letter O with Diaeresis
|
||||
map.insert("\u{011F}".to_string(), "g".to_string()); // Latin Small Letter G with Breve
|
||||
map.insert("\u{0130}".to_string(), "I".to_string()); // Latin Capital Letter I with Dot Above
|
||||
map.insert("\u{0259}".to_string(), "e".to_string()); // Latin Small Letter Schwa (TODO: Inaccurate?)
|
||||
map.insert("\u{012B}".to_string(), "i".to_string()); // Latin Small Letter I with Macron
|
||||
map.insert("\u{1D3A}".to_string(), "n".to_string()); // Modifier Letter Capital N
|
||||
map.insert("\u{01D0}".to_string(), "i".to_string()); // Latin Small Letter I with Caron
|
||||
map.insert("\u{014D}".to_string(), "o".to_string()); // Latin Small Letter O with Macron
|
||||
map.insert("\u{0101}".to_string(), "a".to_string()); // Latin Small Letter A with Macron
|
||||
map.insert("\u{00F9}".to_string(), "u".to_string()); // Latin Small Letter U with Grave
|
||||
map.insert("\u{01Ce}".to_string(), "a".to_string()); // Latin Small Letter A with Caron
|
||||
map
|
||||
});
|
||||
|
||||
pub fn latin_to_ascii(input_text: &str) -> String {
|
||||
let segmented = UnicodeSegmentation::graphemes(input_text, true)
|
||||
.map(|segment| {
|
||||
LATIN_CHARACTER_MAP.get(segment)
|
||||
.map(|replace| replace.as_str())
|
||||
.unwrap_or(segment)
|
||||
})
|
||||
.collect::<Vec<&str>>();
|
||||
|
||||
segmented.join("")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::latin_alphabet::latin_to_ascii;
|
||||
|
||||
#[test]
|
||||
fn test_latin_to_ascii() {
|
||||
assert_eq!(latin_to_ascii("pokémon"), "pokemon".to_string());
|
||||
assert_eq!(latin_to_ascii("POKÉMON"), "POKEMON".to_string());
|
||||
assert_eq!(latin_to_ascii("Æther"), "AEther".to_string());
|
||||
assert_eq!(latin_to_ascii("æther"), "aether".to_string());
|
||||
// Almost exhaustive
|
||||
assert_eq!(latin_to_ascii("ÀÁÂÃÄÅ"), "AAAAAA".to_string());
|
||||
assert_eq!(latin_to_ascii("Æ"), "AE".to_string());
|
||||
assert_eq!(latin_to_ascii("Ç"), "C".to_string());
|
||||
assert_eq!(latin_to_ascii("ÈÉÊË"), "EEEE".to_string());
|
||||
assert_eq!(latin_to_ascii("ÌÍÎÏ"), "IIII".to_string());
|
||||
assert_eq!(latin_to_ascii("ÒÓÔÕÖØ"), "OOOOOO".to_string());
|
||||
assert_eq!(latin_to_ascii("ÙÚÛÜ"), "UUUU".to_string());
|
||||
assert_eq!(latin_to_ascii("Ý"), "Y".to_string());
|
||||
assert_eq!(latin_to_ascii("àáâãäå"), "aaaaaa".to_string());
|
||||
assert_eq!(latin_to_ascii("æ"), "ae".to_string());
|
||||
assert_eq!(latin_to_ascii("ç"), "c".to_string());
|
||||
assert_eq!(latin_to_ascii("èéêë"), "eeee".to_string());
|
||||
assert_eq!(latin_to_ascii("ìíîï"), "iiii".to_string());
|
||||
}
|
||||
}
|
||||
@@ -10,3 +10,4 @@
|
||||
pub (crate) const BANNED_SLURS : &'static str = include_str!("../../../../db/banned_slurs.txt");
|
||||
|
||||
pub mod check_for_slurs;
|
||||
pub mod latin_alphabet;
|
||||
Reference in new issue
Block a user