UNPKG

node-profanity-filter

Version:

A Node.js profanity filter with support for exact matching, obfuscated word detection, and customizable replacement.

67 lines (66 loc) 1.92 kB
class ACNode { children = {}; fail = null; output = []; constructor() { this.fail = this; } } export class AhoCorasick { root = new ACNode(); constructor(words = []) { this.add(words); this.build(); } add(input) { const words = Array.isArray(input) ? input : [input]; for (const word of words) { let node = this.root; for (const ch of word) { node = node.children[ch] ??= new ACNode(); } node.output.push(word); } } build() { const queue = []; for (const child of Object.values(this.root.children)) { child.fail = this.root; queue.push(child); } let qh = 0; while (qh < queue.length) { const current = queue[qh++]; for (const [ch, child] of Object.entries(current.children)) { let fail = current.fail; while (fail !== this.root && !fail.children[ch]) { fail = fail.fail; } child.fail = fail.children[ch] ?? this.root; child.output.push(...child.fail.output); queue.push(child); } } } search(text) { let node = this.root; const matches = []; for (let i = 0; i < text.length; i++) { const ch = text[i]; while (node !== this.root && !node.children[ch]) { node = node.fail; } node = node.children[ch] ?? this.root; if (node.output.length) { for (const w of node.output) { matches.push({ word: w, start: i - w.length + 1, end: i }); } } } return matches; } }