package main import ( "fmt" "regexp" "strings" ) type RuleDetail struct { RuleRaw string RequiredMatched []string ExcludedMatched []string Matched bool } type MatchResult struct { Matched bool MatchedRules []string FailedRules []string Details []RuleDetail } func parseRule(rule string) (required []string, minCount int, excluded []string) { rule = strings.TrimSpace(rule) if strings.Contains(rule, "^") { // 复合规则 (A|B|C)N^(X|Y|Z) re := regexp.MustCompile(`^\(([^)]+)\)(\d+)\^\(([^)]+)\)$`) matches := re.FindStringSubmatch(rule) if len(matches) != 4 { panic("复合规则格式错误:" + rule) } required = strings.Split(matches[1], "|") minCount = atoi(matches[2]) excluded = strings.Split(matches[3], "|") } else { // 简单规则 (A|B|C) re := regexp.MustCompile(`^\(([^)]+)\)$`) matches := re.FindStringSubmatch(rule) if len(matches) != 2 { panic("简单规则格式错误:" + rule) } required = strings.Split(matches[1], "|") minCount = 1 excluded = nil } return } func atoi(s string) int { var i int fmt.Sscanf(s, "%d", &i) return i } func matchSingleRule(text string, rule string) RuleDetail { required, minCount, excluded := parseRule(rule) detail := RuleDetail{ RuleRaw: rule, } for _, kw := range required { if strings.Contains(text, kw) { detail.RequiredMatched = append(detail.RequiredMatched, kw) } } for _, ex := range excluded { if strings.Contains(text, ex) { detail.ExcludedMatched = append(detail.ExcludedMatched, ex) } } detail.Matched = len(detail.RequiredMatched) >= minCount && len(detail.ExcludedMatched) == 0 return detail } func MatchAllRules(text string, ruleStr string) MatchResult { rules := splitRules(ruleStr) res := MatchResult{} for _, rule := range rules { detail := matchSingleRule(text, rule) res.Details = append(res.Details, detail) if detail.Matched { res.MatchedRules = append(res.MatchedRules, rule) } else { res.FailedRules = append(res.FailedRules, rule) } } res.Matched = len(res.MatchedRules) > 0 return res } // 支持用逗号分割时括号内可能也有逗号的情况 func splitRules(s string) []string { var res []string start := 0 level := 0 for i, c := range s { if c == '(' { level++ } else if c == ')' { level-- } else if c == ',' && level == 0 { res = append(res, strings.TrimSpace(s[start:i])) start = i + 1 } } res = append(res, strings.TrimSpace(s[start:])) return res }