// Утилита для фильтрации нежелательного контента const Filter = require('bad-words'); const fs = require('fs'); const path = require('path'); // Список русских нецензурных слов и других запрещенных слов const russianBadWords = [ 'блядь', 'хуй', 'пизда', 'ебать', 'ебал', 'ебло', 'хуесос', 'пидор', 'пидорас', 'мудак', 'говно', 'залупа', 'хер', 'манда', 'спермоед', 'шлюха', 'соска', 'шалава', 'дебил', 'дрочить', 'дрочка', 'ебанутый', 'выродок', 'шмара', 'сука', 'членосос', 'гандон', 'гондон', 'гнида', 'вагина', 'хуи', 'жопа', 'шлюхи', 'проститутка' ]; // Список запрещенных слов и фраз для дейтинг-приложения const datingAppBadWords = [ 'проститутка', 'интим', 'секс за деньги', 'эскорт', 'интим услуги', 'заплачу', 'заплати', 'минет', 'массаж с интимом' ]; /** * Загружает список запрещенных слов из файла * @param {string} filePath - Путь к файлу со списком запрещенных слов * @return {Array} - Массив запрещенных слов */ function loadBadWordsFromFile(filePath) { try { if (fs.existsSync(filePath)) { const content = fs.readFileSync(filePath, 'utf8'); const words = content.split('\n') .map(word => word.trim()) .filter(word => word && !word.startsWith('//') && word.length >= 3); console.log(`Загружено ${words.length} запрещенных слов из файла ${filePath}`); return words; } } catch (error) { console.error(`Ошибка при загрузке слов из файла ${filePath}:`, error.message); } return []; } class ProfanityFilter { constructor() { // Создаем экземпляр фильтра с английскими словами по умолчанию this.filter = new Filter({ placeHolder: '*' }); // Загружаем слова из файлов const russianFileWords = loadBadWordsFromFile(path.join(__dirname, 'words.txt')); const englishFileWords = loadBadWordsFromFile(path.join(__dirname, 'en.txt')); // Объединяем все источники запрещенных слов const allBadWords = [ ...russianBadWords, ...datingAppBadWords, ...russianFileWords, ...englishFileWords ]; // Добавляем все слова в фильтр this.filter.addWords(...allBadWords); // Создаем регулярные выражения для проверки производных слов this.generateWordPatterns(allBadWords); console.log(`Всего загружено ${allBadWords.length} запрещенных слов`); } /** * Создает регулярные выражения для проверки производных слов * @param {Array} words - Список базовых запрещённых слов */ generateWordPatterns(words) { this.wordPatterns = words .filter(word => word && word.length >= 3) // Снижаем минимальную длину до 3 символов .map(word => { // Создаем шаблон с учетом возможных разделителей и замен символов const baseWord = word .replace(/[еёо]/g, '[еёо]') // Учитываем замену е/ё/о .replace(/а/g, '[аa@]') // Учитываем замену а на a латинскую или @ .replace(/о/g, '[оo0]') // Учитываем замену о на o латинскую или 0 .replace(/е/g, '[еe]') // Учитываем замену е на e латинскую .replace(/с/g, '[сc]') // Учитываем замену с на c латинскую .replace(/р/g, '[рp]') // Учитываем замену р на p латинскую .replace(/х/g, '[хx]') // Учитываем замену х на x латинскую .replace(/у/g, '[уy]') // Учитываем замену у на y латинскую .replace(/и/g, '[иi]'); // Учитываем замену и на i // Создаем регулярку, которая учитывает: // - возможные разделители между буквами (точки, пробелы, дефисы) // - возможные окончания слов const chars = baseWord.split(''); const patternWithSeparators = chars.join('[\\s\\._\\-]*'); return new RegExp(`\\b${patternWithSeparators}[а-яёa-z]*\\b`, 'i'); }); } /** * Проверяет, содержит ли текст запрещенные слова или их производные * @param {string} text - Текст для проверки * @return {boolean} - true, если текст содержит запрещенные слова, иначе false */ hasProfanity(text) { if (!text) return false; // Нормализуем текст, убирая лишние символы и разделители const normalizedText = text.toLowerCase() .replace(/[\s\._\-]+/g, ''); // Удаляем пробелы, точки, подчеркивания, дефисы // Проверяем сначала стандартным методом библиотеки bad-words if (this.filter.isProfane(normalizedText) || this.filter.isProfane(text.toLowerCase())) { return true; } // Дополнительная проверка на производные слова через регулярные выражения return this.wordPatterns.some(pattern => pattern.test(text.toLowerCase())); } /** * Проверяет, содержит ли объект запрещенные слова в указанных полях * @param {Object} obj - Объект для проверки * @param {Array} fields - Массив имен полей для проверки * @return {Object} - Объект с результатами проверки { isProfane: boolean, field: string|null } */ validateObject(obj, fields) { for (const field of fields) { if (obj[field] && this.hasProfanity(obj[field])) { return { isProfane: true, field }; } } return { isProfane: false, field: null }; } /** * Заменяет запрещенные слова в тексте на звездочки * @param {string} text - Исходный текст * @return {string} - Очищенный текст */ clean(text) { if (!text) return ''; // Сначала используем стандартный метод библиотеки let cleanedText = this.filter.clean(text); // Затем проверяем на производные слова и заменяем их this.wordPatterns.forEach(pattern => { cleanedText = cleanedText.replace(pattern, match => '*'.repeat(match.length)); }); return cleanedText; } /** * Добавляет новое запрещенное слово в фильтр * @param {string|Array} words - Слово или массив слов для добавления */ addWords(words) { // Добавляем слова в стандартный фильтр this.filter.addWords(words); // Если слова переданы как массив if (Array.isArray(words)) { this.generateWordPatterns(words); } else { // Если передано одно слово this.generateWordPatterns([words]); } } } // Экспортируем экземпляр фильтра для использования в приложении const profanityFilter = new ProfanityFilter(); module.exports = profanityFilter;