UNPKG

modern-ahocorasick

Version:
115 lines (114 loc) 3.04 kB
// src/index.ts var AhoCorasick = class { gotoFn; output; failure; constructor(keywords) { const { failure, gotoFn, output } = this._buildTables(keywords); this.gotoFn = gotoFn; this.output = output; this.failure = failure; } _buildTables(keywords) { const gotoFn = { 0: {} }; const output = {}; let state = 0; for (const word of keywords) { const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" }); const iterator = segmenter.segment(word)[Symbol.iterator](); let curr = 0; for (const l of iterator) { const segment = l.segment; if (gotoFn[curr] && segment in gotoFn[curr]) { curr = gotoFn[curr][segment]; } else { state++; gotoFn[curr][segment] = state; gotoFn[state] = {}; curr = state; output[state] = []; } } output[curr].push(word); } const failure = {}; const xs = []; for (const l in gotoFn[0]) { const state2 = gotoFn[0][l]; failure[state2] = 0; xs.push(state2); } while (xs.length > 0) { const r = xs.shift(); if (r !== void 0) { for (const l in gotoFn[r]) { const s = gotoFn[r][l]; xs.push(s); let state2 = failure[r]; while (state2 > 0 && !(l in gotoFn[state2])) { state2 = failure[state2]; } if (l in gotoFn[state2]) { const fs = gotoFn[state2][l]; failure[s] = fs; output[s] = [...output[s], ...output[fs]]; } else { failure[s] = 0; } } } } return { gotoFn, output, failure }; } search(str) { let state = 0; const results = []; const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" }); const iterator = segmenter.segment(str)[Symbol.iterator](); let count = -1; for (const l of iterator) { const segment = l.segment; count++; while (state > 0 && !(segment in this.gotoFn[state])) { state = this.failure[state]; } if (!(segment in this.gotoFn[state])) { continue; } state = this.gotoFn[state][segment]; if (this.output[state].length > 0) { const foundStrs = this.output[state]; results.push([count, foundStrs]); } } return results; } match(str) { let state = 0; const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" }); const iterator = segmenter.segment(str)[Symbol.iterator](); for (const l of iterator) { const segment = l.segment; while (state > 0 && !(segment in this.gotoFn[state])) { state = this.failure[state]; } if (!(segment in this.gotoFn[state])) { continue; } state = this.gotoFn[state][segment]; if (this.output[state].length > 0) { return true; } } return false; } }; export { AhoCorasick as default };