|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"git.noahlan.cn/northlan/ntools-go/stringn/ac"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
CMD struct {
|
|
|
|
IsCMD bool // 是否CMD
|
|
|
|
Arr []string // 具体CMD []string
|
|
|
|
}
|
|
|
|
Parser struct {
|
|
|
|
ac ac.AhoCorasick
|
|
|
|
distinct bool // 命令是否去重
|
|
|
|
allKeyArr []string
|
|
|
|
keywordMap map[string]struct{}
|
|
|
|
}
|
|
|
|
ParserBuilder struct {
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func NewCMDParser(distinct bool, keys ...string) *Parser {
|
|
|
|
p := &Parser{
|
|
|
|
distinct: distinct,
|
|
|
|
keywordMap: make(map[string]struct{}),
|
|
|
|
allKeyArr: make([]string, 0, len(keys)),
|
|
|
|
}
|
|
|
|
for _, keyword := range keys {
|
|
|
|
p.keywordMap[keyword] = struct{}{}
|
|
|
|
p.allKeyArr = append(p.allKeyArr, keyword)
|
|
|
|
}
|
|
|
|
builder := ac.NewAhoCorasickBuilder(ac.Opts{
|
|
|
|
AsciiCaseInsensitive: true,
|
|
|
|
MatchOnlyWholeWords: false,
|
|
|
|
MatchKind: ac.LeftMostLongestMatch,
|
|
|
|
DFA: true,
|
|
|
|
})
|
|
|
|
p.ac = builder.Build(p.allKeyArr)
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Parser) ParseTest(content string) []ac.Match {
|
|
|
|
return p.ac.FindAll(content)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetDistinct 设置命令去重
|
|
|
|
func (p *Parser) SetDistinct(distinct bool) {
|
|
|
|
p.distinct = distinct
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse 从弹幕内容解析命令
|
|
|
|
func (p *Parser) Parse(content string) *CMD {
|
|
|
|
// 移除多余空格,小写
|
|
|
|
tmpContent := strings.ToLower(strings.TrimSpace(content))
|
|
|
|
|
|
|
|
allKeyLen := 0
|
|
|
|
matchedKeys := make([]string, 0)
|
|
|
|
|
|
|
|
iter := p.ac.Iter(tmpContent)
|
|
|
|
for next := iter.Next(); next != nil; next = iter.Next() {
|
|
|
|
tmp := p.allKeyArr[next.Pattern()]
|
|
|
|
matchedKeys = append(matchedKeys, tmp)
|
|
|
|
allKeyLen += len(tmp)
|
|
|
|
}
|
|
|
|
isCMD := len(tmpContent) <= allKeyLen
|
|
|
|
|
|
|
|
// 避免同类型指令重复
|
|
|
|
arrMap := make(map[rune]struct{})
|
|
|
|
var matchedCmdArr []string
|
|
|
|
if p.distinct && isCMD {
|
|
|
|
matchedCmdArr = make([]string, 0, len(matchedKeys))
|
|
|
|
for _, s := range matchedKeys {
|
|
|
|
sRune := []rune(s)
|
|
|
|
if _, ok := arrMap[sRune[0]]; !ok {
|
|
|
|
arrMap[sRune[0]] = struct{}{}
|
|
|
|
matchedCmdArr = append(matchedCmdArr, s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resp := &CMD{IsCMD: isCMD, Arr: matchedKeys}
|
|
|
|
if p.distinct {
|
|
|
|
resp.Arr = matchedCmdArr
|
|
|
|
}
|
|
|
|
return resp
|
|
|
|
}
|