You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.0 KiB
Go

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 从弹幕内容解析命令
// distinct 是否去重
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
}