@dwcks/bad-word-filter-vi-en
Version:
Thư viện lọc từ xấu tiếng Việt và tiếng Anh
108 lines (107 loc) • 4.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.BadWordFilter = void 0;
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
class BadWordFilter {
constructor(badWords) {
this.regex = null;
this.badWords = new Set(badWords);
}
static async create(badWordsOrFilePath) {
let badWords = [];
if (Array.isArray(badWordsOrFilePath)) {
badWords = badWordsOrFilePath;
}
else {
const filePath = typeof badWordsOrFilePath === 'string'
? badWordsOrFilePath
: path.resolve(__dirname, 'bad-words.txt');
try {
const fileContent = await fs.readFile(filePath, 'utf-8');
badWords = fileContent
.split('\n')
.map((word) => word.trim())
.filter((word) => word.length > 0);
}
catch (error) {
console.warn(`Không đọc được file ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
badWords = [];
}
}
// Chuẩn hóa từ xấu: chuyển về chữ thường
badWords = badWords.map((word) => word.toLowerCase());
// Sắp xếp từ dài đến ngắn để ưu tiên cụm từ
badWords.sort((a, b) => b.length - a.length);
return new BadWordFilter(badWords);
}
escapeRegex(text) {
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
normalizeText(text) {
// Chuyển về chữ thường và chuẩn hóa Unicode
let normalized = text.toLowerCase().normalize('NFKD');
// Loại bỏ dấu câu và ký tự đặc biệt, giữ lại chữ cái, số và ký tự tiếng Việt
normalized = normalized.replace(/[^a-z0-9\s\u00C0-\u1EF9]/g, '');
// Loại bỏ khoảng trắng thừa
normalized = normalized.replace(/\s+/g, ' ').trim();
return normalized;
}
buildRegex() {
if (!this.regex) {
// Tạo regex cho từng từ, cho phép ký tự đặc biệt xen kẽ
const escapedWords = Array.from(this.badWords).map((word) => {
// Thêm \S* giữa các ký tự để khớp các biến thể như f***k
const chars = word.split('');
return chars.map((c) => this.escapeRegex(c) + '\\S*').join('');
});
this.regex = new RegExp(`(${escapedWords.join('|')})`, 'gi');
}
return this.regex;
}
hasBadWord(comment) {
if (!comment || typeof comment !== 'string')
return false;
const normalizedComment = this.normalizeText(comment);
return this.buildRegex().test(comment) || this.buildRegex().test(normalizedComment);
}
filter(comment, mask = '*') {
if (!comment || typeof comment !== 'string')
return comment;
return comment.replace(this.buildRegex(), (match) => mask.repeat(match.length));
}
}
exports.BadWordFilter = BadWordFilter;