zitcher
Version:
字符串匹配算法相关js实现
140 lines (133 loc) • 3.16 kB
JavaScript
/**
* 多模式串匹配,ac自动机的js实现
* @param {array} modes 模式串数组
*/
function ac(modes) {
var root = new AcNode(0)
this.lastState = 1
//通过字符串数组构建trie结构
for (var i = 0; i < modes.length; i++) {
var mode = modes[i]
var arr = mode.split('')
var last = root
for (var j = 0; j < arr.length; j++) {
var ch = arr[j]
last = last.next(ch, this.lastState++)
}
last.finish = true
last.mode = mode
}
//构建failure表做失陪跳转
var failure = new Array(this.lastState)
var queue = []
var nextChars = root.nextChars()
for (i = 0; i < nextChars.length; i++) {
var nextNode = root.next(nextChars[i])
failure[nextNode.state] = root
queue.push(nextNode)
}
while (queue.length != 0) {
var known = queue.shift()
nextChars = known.nextChars()
for (j = 0; j < nextChars.length; j++) {
var nxt = known.next(nextChars[j])
last = failure[known.state]
while (last != root && last.next(nextChars[j])) {
last = failure[last.state]
}
if (!last.next[nextChars[j]]) {
failure[nxt.state] = root
} else {
failure[nxt.state] = last.next[nextChars[j]]
}
queue.push(nxt)
}
}
this.root = root
this.failure = failure
}
/**
* 查找第一个出现的模式串
* @param {string} target 目标串
*/
ac.prototype.findFirst = function (target) {
var node = this.root
var chars = target.split('')
for (var i = 0; i < chars.length; i++) {
var next = node.next(chars[i])
if (next != null) {
node = next
} else {
if (i == 0 || node == this.root) {
continue
}
--i
node = this.failure[node.state]
}
if (node.finish) {
return {
mode: node.mode,
start: i - node.mode.length + 1
}
}
}
}
ac.prototype.findAll = function (target) {
var results = []
var node = this.root
var chars = target.split('')
for (var i = 0; i < chars.length; i++) {
var next = node.next(chars[i])
if (next != null) {
node = next
} else {
if (i == 0 || node == this.root) {
continue
}
--i
node = this.failure[node.state]
}
if (node.finish) {
results.push({
mode: node.mode,
start: i - node.mode.length + 1
})
if (i == 0 || node == this.root) {
continue
}
i = i - node.mode.length + 1
node = this.failure[node.state]
}
}
return results
}
/**
* acTrie的节点
* @param {number} state 状态
*/
function AcNode(state) {
this.state = state
this.finish = false
}
/**
* 添加/获取下一个节点
* @param {char} ch 下一个字符
* @param {AcNode} node 下一个节点
*/
AcNode.prototype.next = function (ch, state) {
if (!this.nodes)
this.nodes = {}
if (state && !this.nodes[ch])
this.nodes[ch] = new AcNode(state)
return this.nodes[ch]
}
AcNode.prototype.nextChars = function () {
var result = []
for (var key in this.nodes) {
if (this.nodes.hasOwnProperty(key)) {
result.push(key)
}
}
return result
}
module.exports = ac