forked from Muzifs/LGBot
Улучшение системы фильтрации матов
Добавлено: - разделение словаря на базовый (в репозитории) и кастомный (добавления модераторов) - поддержка английских бранных слов и их обфускации - тесты для проверки ловли матов и ложных срабатываний - автоматическая категоризация добавленных модераторами слов Изменено: - переработан механизм проверки текста на маты - базовый словарь объединён с серверным и переведён в новый формат - короткие слова теперь проверяются как начало слова, а не пропускаются Удалено: - повреждённая запись exception урод из базового словаря
This commit is contained in:
1 parent
b38c24f775
commit
cfc52247a0
4 files changed
+942
-518
No files matched your search
@@ -28,6 +28,9 @@ bot.log
|
||||
# Databases
|
||||
users.db
|
||||
|
||||
# Custom moderator wordlist (generated at runtime)
|
||||
src/data/bad_words_custom.json
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
+611
-451
File diff suppressed because it is too large.
Load diff
+132
-67
@@ -1,96 +1,148 @@
|
||||
{
|
||||
"patterns": {
|
||||
"whole_word": [
|
||||
"гандон",
|
||||
"гей",
|
||||
"гнид",
|
||||
"гнида",
|
||||
"гомик",
|
||||
"гомос",
|
||||
"даун",
|
||||
"дебил",
|
||||
"гандон",
|
||||
"мразь",
|
||||
"мраз",
|
||||
"козел",
|
||||
"козл",
|
||||
"урод",
|
||||
"урода",
|
||||
"тварь",
|
||||
"твар",
|
||||
"мраз",
|
||||
"мразь",
|
||||
"падла",
|
||||
"гнида",
|
||||
"гнид"
|
||||
"твар",
|
||||
"тварь",
|
||||
"урод",
|
||||
"урода"
|
||||
],
|
||||
"word_start": [
|
||||
"хуй",
|
||||
"хуе",
|
||||
"хуи",
|
||||
"хую",
|
||||
"хуя",
|
||||
"хер",
|
||||
"бля",
|
||||
"пизд",
|
||||
"пизж",
|
||||
"пезд",
|
||||
"ебал",
|
||||
"ебан",
|
||||
"ебат",
|
||||
"ебош",
|
||||
"ебля",
|
||||
"ебет",
|
||||
"ебля",
|
||||
"ебош",
|
||||
"ебут",
|
||||
"ебуч",
|
||||
"жоп",
|
||||
"жёп"
|
||||
"жёп",
|
||||
"пезд",
|
||||
"пизд",
|
||||
"пизж",
|
||||
"хер",
|
||||
"хуе",
|
||||
"хуи",
|
||||
"хуй",
|
||||
"хую",
|
||||
"хуя"
|
||||
],
|
||||
"contains": [
|
||||
"ахуе",
|
||||
"блядь",
|
||||
"блять",
|
||||
"сука",
|
||||
"суки",
|
||||
"сучк",
|
||||
"сучар",
|
||||
"мудак",
|
||||
"мудил",
|
||||
"муди",
|
||||
"долбоеб",
|
||||
"долбаеб",
|
||||
"уебан",
|
||||
"уебок",
|
||||
"хуесос",
|
||||
"пидор",
|
||||
"пидар",
|
||||
"педик",
|
||||
"педр",
|
||||
"шлюх",
|
||||
"шалав",
|
||||
"еблан",
|
||||
"говн",
|
||||
"срать",
|
||||
"сраль",
|
||||
"серун",
|
||||
"дрочи",
|
||||
"дроч",
|
||||
"залуп",
|
||||
"ублюдо",
|
||||
"ублюд",
|
||||
"сволочь",
|
||||
"сволоч",
|
||||
"впизду",
|
||||
"выблядо",
|
||||
"хуета",
|
||||
"хуйн",
|
||||
"говн",
|
||||
"долбаеб",
|
||||
"долбоеб",
|
||||
"дроч",
|
||||
"дрочи",
|
||||
"еблан",
|
||||
"залуп",
|
||||
"захуя",
|
||||
"звиздюк",
|
||||
"мудак",
|
||||
"муди",
|
||||
"мудил",
|
||||
"нахер",
|
||||
"нахуй",
|
||||
"охуе",
|
||||
"охуи",
|
||||
"охуя",
|
||||
"нахуй",
|
||||
"нахер",
|
||||
"похуй",
|
||||
"педик",
|
||||
"педр",
|
||||
"пидар",
|
||||
"пидор",
|
||||
"попизд",
|
||||
"похер",
|
||||
"захуя",
|
||||
"ахуе",
|
||||
"впизду",
|
||||
"попизд"
|
||||
"похуй",
|
||||
"сволоч",
|
||||
"сволочь",
|
||||
"серун",
|
||||
"сирик",
|
||||
"срака",
|
||||
"сраль",
|
||||
"срать",
|
||||
"ссался",
|
||||
"сука",
|
||||
"суки",
|
||||
"сучар",
|
||||
"сучк",
|
||||
"сытса",
|
||||
"ублюд",
|
||||
"ублюдо",
|
||||
"уебан",
|
||||
"уебок",
|
||||
"хуесос",
|
||||
"хуета",
|
||||
"хуйн",
|
||||
"шалав",
|
||||
"шлюх"
|
||||
],
|
||||
"en": [
|
||||
"asshole",
|
||||
"assholes",
|
||||
"bitch",
|
||||
"bitches",
|
||||
"bitchy",
|
||||
"bliad",
|
||||
"bliat",
|
||||
"blya",
|
||||
"blyat",
|
||||
"ebal",
|
||||
"ebany",
|
||||
"ebat",
|
||||
"fck",
|
||||
"fuck",
|
||||
"fucked",
|
||||
"fucker",
|
||||
"fucking",
|
||||
"fucks",
|
||||
"fuk",
|
||||
"fuuk",
|
||||
"gandon",
|
||||
"gandona",
|
||||
"hui",
|
||||
"huilo",
|
||||
"huy",
|
||||
"mudak",
|
||||
"mudila",
|
||||
"nahui",
|
||||
"pedik",
|
||||
"pidor",
|
||||
"pizda",
|
||||
"pizdec",
|
||||
"pizdets",
|
||||
"pizdetsa",
|
||||
"pizdu",
|
||||
"pohui",
|
||||
"shit",
|
||||
"shitting",
|
||||
"shitty",
|
||||
"suchka",
|
||||
"suka",
|
||||
"suki",
|
||||
"xyu",
|
||||
"xyй"
|
||||
]
|
||||
},
|
||||
"exceptions": [
|
||||
"bloatware",
|
||||
"аблятив",
|
||||
"абляут",
|
||||
"абляционный",
|
||||
@@ -121,6 +173,7 @@
|
||||
"гребу",
|
||||
"гребут",
|
||||
"даунгрейд",
|
||||
"даунгрейт",
|
||||
"догребать",
|
||||
"документ",
|
||||
"документы",
|
||||
@@ -129,6 +182,7 @@
|
||||
"дубляж",
|
||||
"дубляжем",
|
||||
"дубляжом",
|
||||
"забляковать",
|
||||
"завихрение",
|
||||
"завихренние",
|
||||
"заглублявший",
|
||||
@@ -140,6 +194,7 @@
|
||||
"зарыблять",
|
||||
"застрахуйся",
|
||||
"злоупотреблявший",
|
||||
"злоупотреблял",
|
||||
"злоупотреблять",
|
||||
"злоупотребляющий",
|
||||
"истреблявший",
|
||||
@@ -165,6 +220,7 @@
|
||||
"нагребать",
|
||||
"наскребать",
|
||||
"нахлебаться",
|
||||
"небалансным",
|
||||
"небудь",
|
||||
"обляпавший",
|
||||
"обляпался",
|
||||
@@ -173,6 +229,8 @@
|
||||
"обляпаться",
|
||||
"обляпывать",
|
||||
"обляпываться",
|
||||
"облёк",
|
||||
"облёкся",
|
||||
"обособлявший",
|
||||
"обособлявшийся",
|
||||
"обособляйся",
|
||||
@@ -229,12 +287,16 @@
|
||||
"пособлявший",
|
||||
"пособлять",
|
||||
"пособляющий",
|
||||
"потребление",
|
||||
"потреблявший",
|
||||
"потребляемый",
|
||||
"потребляет",
|
||||
"потребляла",
|
||||
"потреблялась",
|
||||
"потреблять",
|
||||
"потребляться",
|
||||
"потребляют",
|
||||
"потребляющий",
|
||||
"потребление",
|
||||
"потребует",
|
||||
"потребуется",
|
||||
"похлебать",
|
||||
@@ -281,6 +343,7 @@
|
||||
"сиагейты",
|
||||
"скоблящий",
|
||||
"скоблящийся",
|
||||
"скорблящий",
|
||||
"скребу",
|
||||
"скребут",
|
||||
"слюбляться",
|
||||
@@ -290,14 +353,15 @@
|
||||
"стебать",
|
||||
"стебля",
|
||||
"схлебать",
|
||||
"твар",
|
||||
"требование",
|
||||
"требовать",
|
||||
"требует",
|
||||
"требуем",
|
||||
"требует",
|
||||
"требуется",
|
||||
"требуха",
|
||||
"требую",
|
||||
"требуют",
|
||||
"требуха",
|
||||
"углублявший",
|
||||
"углублявшийся",
|
||||
"углублять",
|
||||
@@ -310,15 +374,15 @@
|
||||
"уподобляться",
|
||||
"уподобляющий",
|
||||
"уподобляющийся",
|
||||
"употребление",
|
||||
"употреблявший",
|
||||
"употреблявшийся",
|
||||
"употребляемый",
|
||||
"употреблять",
|
||||
"употребляться",
|
||||
"употребляю",
|
||||
"употребляющий",
|
||||
"употребляющийся",
|
||||
"употребление",
|
||||
"употребляю",
|
||||
"усугублявший",
|
||||
"усугублявшийся",
|
||||
"усугубляемый",
|
||||
@@ -328,9 +392,10 @@
|
||||
"усугубляющийся",
|
||||
"ущерблять",
|
||||
"ущербляться",
|
||||
"херметичность",
|
||||
"хлебать",
|
||||
"чебурнет",
|
||||
"шоудаун",
|
||||
"эчпочмак"
|
||||
],
|
||||
"_comment": "whole_word - только целые слова с границами \\b, word_start - только начало слова, contains - любое вхождение (мин. 4 буквы в коде)"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
# Тесты для системы обнаружения бранных слов
|
||||
# Запуск: python -m unittest tests.test_bad_words
|
||||
|
||||
import sys
|
||||
import os
|
||||
import unittest
|
||||
|
||||
# Добавляем src в путь для импорта
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
|
||||
|
||||
from bad_words import contains_bad_word, get_bad_words_from_text, normalize_text
|
||||
|
||||
|
||||
class TestNormalizeText(unittest.TestCase):
|
||||
"""Тесты нормализации текста"""
|
||||
|
||||
def test_lowercase(self):
|
||||
self.assertEqual(normalize_text('ХЕР'), 'хер')
|
||||
|
||||
def test_remove_yo(self):
|
||||
self.assertEqual(normalize_text('хЁр'), 'хер')
|
||||
|
||||
def test_remove_obfuscation_ru(self):
|
||||
self.assertEqual(normalize_text('х*е*р'), 'хер')
|
||||
self.assertEqual(normalize_text('х.е.р'), 'хер')
|
||||
self.assertEqual(normalize_text('х_е_р'), 'хер')
|
||||
self.assertEqual(normalize_text('х-е-р'), 'хер')
|
||||
|
||||
def test_collapse_spaces_ru(self):
|
||||
self.assertEqual(normalize_text('х е р'), 'хер')
|
||||
self.assertEqual(normalize_text('х е р'), 'хер')
|
||||
|
||||
def test_collapse_repeated_letters_ru(self):
|
||||
self.assertEqual(normalize_text('хххеееррр'), 'хер')
|
||||
self.assertEqual(normalize_text('хууууй'), 'хуй')
|
||||
|
||||
|
||||
class TestContainsBadWordPositive(unittest.TestCase):
|
||||
"""Позитивные тесты: должны ловиться"""
|
||||
|
||||
def test_russian_short_word_start(self):
|
||||
"""Короткие слова, которые являются началом слова"""
|
||||
self.assertTrue(contains_bad_word('хер'))
|
||||
self.assertTrue(contains_bad_word('херня'))
|
||||
self.assertTrue(contains_bad_word('нахер'))
|
||||
self.assertTrue(contains_bad_word('похер'))
|
||||
self.assertTrue(contains_bad_word('херовый'))
|
||||
self.assertTrue(contains_bad_word('бля'))
|
||||
self.assertTrue(contains_bad_word('блядь'))
|
||||
self.assertTrue(contains_bad_word('хуй'))
|
||||
self.assertTrue(contains_bad_word('хуйло'))
|
||||
self.assertTrue(contains_bad_word('жопа'))
|
||||
|
||||
def test_russian_contains(self):
|
||||
"""Слова, содержащие бранные подстроки"""
|
||||
self.assertTrue(contains_bad_word('сука'))
|
||||
self.assertTrue(contains_bad_word('пиздец'))
|
||||
self.assertTrue(contains_bad_word('ебать'))
|
||||
self.assertTrue(contains_bad_word('говно'))
|
||||
self.assertTrue(contains_bad_word('дрочить'))
|
||||
self.assertTrue(contains_bad_word('пидор'))
|
||||
self.assertTrue(contains_bad_word('мудак'))
|
||||
self.assertTrue(contains_bad_word('шлюха'))
|
||||
self.assertTrue(contains_bad_word('ублюдок'))
|
||||
|
||||
def test_russian_whole_word(self):
|
||||
"""Точные слова-оскорбления"""
|
||||
self.assertTrue(contains_bad_word('даун'))
|
||||
self.assertTrue(contains_bad_word('дебил'))
|
||||
self.assertTrue(contains_bad_word('урод'))
|
||||
self.assertTrue(contains_bad_word('мразь'))
|
||||
|
||||
def test_english_bad_words(self):
|
||||
"""Английские бранные слова"""
|
||||
self.assertTrue(contains_bad_word('fuck'))
|
||||
self.assertTrue(contains_bad_word('fucking'))
|
||||
self.assertTrue(contains_bad_word('fucker'))
|
||||
self.assertTrue(contains_bad_word('fuck you'))
|
||||
self.assertTrue(contains_bad_word('shit'))
|
||||
self.assertTrue(contains_bad_word('bitch'))
|
||||
self.assertTrue(contains_bad_word('asshole'))
|
||||
|
||||
def test_obfuscated_english(self):
|
||||
"""Обфусцированные английские слова"""
|
||||
self.assertTrue(contains_bad_word('f*ck'))
|
||||
self.assertTrue(contains_bad_word('f.u.c.k'))
|
||||
self.assertTrue(contains_bad_word('f u c k'))
|
||||
self.assertTrue(contains_bad_word('fuuuck'))
|
||||
self.assertTrue(contains_bad_word('f-u-c-k'))
|
||||
|
||||
def test_transliterated_russian(self):
|
||||
"""Русские маты, написанные латиницей"""
|
||||
self.assertTrue(contains_bad_word('xyu'))
|
||||
self.assertTrue(contains_bad_word('hui'))
|
||||
self.assertTrue(contains_bad_word('xyй'))
|
||||
self.assertTrue(contains_bad_word('pizdec'))
|
||||
|
||||
def test_mixed_text(self):
|
||||
"""Бранные слова внутри обычного текста"""
|
||||
self.assertTrue(contains_bad_word('Это просто херня какая-то'))
|
||||
self.assertTrue(contains_bad_word('Ты что, дебил?'))
|
||||
self.assertTrue(contains_bad_word('Он сказал fuck off'))
|
||||
|
||||
|
||||
class TestContainsBadWordNegative(unittest.TestCase):
|
||||
"""Негативные тесты: НЕ должны ловиться"""
|
||||
|
||||
def test_russian_exceptions_from_list(self):
|
||||
"""Слова из списка исключений"""
|
||||
self.assertFalse(contains_bad_word('аблятив'))
|
||||
self.assertFalse(contains_bad_word('абляция'))
|
||||
self.assertFalse(contains_bad_word('влюблять'))
|
||||
self.assertFalse(contains_bad_word('гребля'))
|
||||
self.assertFalse(contains_bad_word('даунгрейд'))
|
||||
self.assertFalse(contains_bad_word('гейтвей'))
|
||||
self.assertFalse(contains_bad_word('гейм'))
|
||||
|
||||
def test_normal_words_with_bad_substrings(self):
|
||||
"""Обычные слова, содержащие бранные корни"""
|
||||
self.assertFalse(contains_bad_word('херметичность'))
|
||||
self.assertFalse(contains_bad_word('скорблящий'))
|
||||
self.assertFalse(contains_bad_word('забляковать'))
|
||||
self.assertFalse(contains_bad_word('обляпать'))
|
||||
self.assertFalse(contains_bad_word('находится')) # содержит "хуй"? нет
|
||||
self.assertFalse(contains_bad_word('класс')) # содержит "асс" - не мат
|
||||
|
||||
def test_english_normal_words(self):
|
||||
"""Обычные английские слова"""
|
||||
self.assertFalse(contains_bad_word('hello'))
|
||||
self.assertFalse(contains_bad_word('assume'))
|
||||
self.assertFalse(contains_bad_word('passion'))
|
||||
self.assertFalse(contains_bad_word('class'))
|
||||
self.assertFalse(contains_bad_word('association'))
|
||||
self.assertFalse(contains_bad_word('document'))
|
||||
|
||||
def test_empty_and_short(self):
|
||||
"""Пустой текст и короткие безобидные строки"""
|
||||
self.assertFalse(contains_bad_word(''))
|
||||
self.assertFalse(contains_bad_word('а'))
|
||||
self.assertFalse(contains_bad_word('привет'))
|
||||
|
||||
|
||||
class TestGetBadWordsFromText(unittest.TestCase):
|
||||
"""Тесты функции получения списка найденных слов"""
|
||||
|
||||
def test_single_word(self):
|
||||
found = get_bad_words_from_text('херня')
|
||||
self.assertIn('хер', found)
|
||||
|
||||
def test_multiple_words(self):
|
||||
found = get_bad_words_from_text('херня и fuck')
|
||||
self.assertIn('хер', found)
|
||||
self.assertIn('fuck', found)
|
||||
|
||||
def test_no_bad_words(self):
|
||||
found = get_bad_words_from_text('абляция и документ')
|
||||
self.assertEqual(found, [])
|
||||
|
||||
|
||||
class TestEdgeCases(unittest.TestCase):
|
||||
"""Дополнительные проверки на ложные срабатывания и сложные обходы"""
|
||||
|
||||
def test_english_word_boundaries(self):
|
||||
"""Обычные английские слова не должны ловиться"""
|
||||
self.assertFalse(contains_bad_word('class'))
|
||||
self.assertFalse(contains_bad_word('passion'))
|
||||
self.assertFalse(contains_bad_word('assignment'))
|
||||
self.assertFalse(contains_bad_word('shifty')) # содержит shift, не shit
|
||||
|
||||
def test_russian_word_boundaries(self):
|
||||
"""Обычные русские слова с бранными корнями"""
|
||||
self.assertFalse(contains_bad_word('херметичность'))
|
||||
self.assertFalse(contains_bad_word('скорблящий'))
|
||||
self.assertFalse(contains_bad_word('забляковать'))
|
||||
self.assertFalse(contains_bad_word('обляпать'))
|
||||
|
||||
def test_mixed_scripts(self):
|
||||
"""Смешанные латиница и кириллица"""
|
||||
self.assertTrue(contains_bad_word('xyй'))
|
||||
self.assertTrue(contains_bad_word('ху й'))
|
||||
|
||||
def test_case_insensitive(self):
|
||||
"""Регистронезависимость"""
|
||||
self.assertTrue(contains_bad_word('FUCK'))
|
||||
self.assertTrue(contains_bad_word('ХерНя'))
|
||||
self.assertTrue(contains_bad_word('БЛЯ'))
|
||||
|
||||
def test_with_punctuation(self):
|
||||
"""Бранные слова с пунктуацией"""
|
||||
self.assertTrue(contains_bad_word('херня!'))
|
||||
self.assertTrue(contains_bad_word('fuck!!!'))
|
||||
self.assertTrue(contains_bad_word('ты, блядь, кто?'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user