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 }