UNPKG

sensitive-word-helper-plus

Version:

基于DFA算法的一个敏感词助手, 可以做步长控制

165 lines (140 loc) 4.11 kB
/** * Created by ChengZheLin on 2019/6/3. * Features: index */ import { Node, Tree } from './core'; interface FilterValue { text?: string | boolean; filter: Array<string>; pass?: boolean; } interface SwhpConstructor { keywords: Array<string>; replacement?: string; step?: number; } class SensitiveWithoutStep extends Tree { /** * 兼容1.1.6 */ static default: any; // 是否替换原文本敏感词 constructor(obj: SwhpConstructor) { super(); const { keywords, step, replacement } = obj; if (!(keywords instanceof Array && keywords.length >= 1)) { console.error('Sensitive-word:未将过滤词数组传入!'); return; } if (typeof replacement === 'string') { this.replacement = replacement; } this.step = 0; // 创建Trie树 for (let item of keywords) { if (!item) continue; this.insert(item.toLocaleUpperCase()); } this._createFailureTable(); } _filterFn( word: string, every: boolean = false, replace: boolean = true ): FilterValue { if (typeof word !== 'string') { console.error('word must be String !') word = '' } let startIndex = 0; let endIndex = startIndex; const wordLen = word.length; let originalWord: string = word; let filterKeywords: Array<string> = []; word = word.toLocaleUpperCase(); // 保存过滤文本 let filterText: string = ''; // 是否通过,无敏感词 let isPass = true; // 正在进行划词判断 let isJudge: boolean = false; let judgeText: string = ''; // 上一个Node与下一个Node let prevNode: Node = this.root; let currNode: Node | boolean; for (endIndex; endIndex <= wordLen; endIndex++) { let key: string = word[endIndex]; let originalKey: string = originalWord[endIndex]; currNode = this.search(key, prevNode.children); if (isJudge && currNode) { if (replace) judgeText += originalKey; prevNode = currNode; continue; } else if (isJudge && prevNode.word) { isPass = false; if (every) break; if (replace) filterText += '*'.repeat(endIndex - startIndex); filterKeywords.push(word.slice(startIndex, endIndex)); } else if (replace) { filterText += judgeText; } if (!currNode) { // 直接在分支上找不到,需要走failure let failure: Node = prevNode.failure; while (failure) { currNode = this.search(key, failure.children); if (currNode) break; failure = failure.failure; } } if (currNode) { judgeText = originalKey; isJudge = true; prevNode = currNode; } else { judgeText = ''; isJudge = false; prevNode = this.root; if (replace && key !== undefined) filterText += originalKey; } startIndex = endIndex; } return { text: replace ? filterText : originalWord, filter: [...new Set(filterKeywords)], pass: isPass }; } /** * 异步快速检测字符串是否无敏感词 * @param word */ every(word: string): Promise<boolean> { return Promise.resolve(this._filterFn(word, true).pass); } /** * 同步快速检测字符串是否无敏感词 * @param word */ everySync(word: string): boolean { return this._filterFn(word, true).pass; } /** * 同步过滤方法 * @param word * @param replace */ filterSync(word: string, replace: boolean = true): FilterValue { return this._filterFn(word, false, replace); } /** * 异步过滤方法 * @param word * @param replace */ async filter(word: string, replace: boolean = true): Promise<FilterValue> { return Promise.resolve(this._filterFn(word, false, replace)); } } SensitiveWithoutStep.default = SensitiveWithoutStep; export = SensitiveWithoutStep;