modern-ahocorasick
Version:
modern-ahocorasick
117 lines (110 loc) • 3.12 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true});// src/index.ts
var AhoCorasick = class {
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;
}
};
exports.default = AhoCorasick;
module.exports = exports.default;