Files
huangguo_server/skd/service/contentreviewser/matcher.go
T
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

115 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package contentreviewser
import (
"sort"
"strings"
"91porn-server/models/v/contentreviewmod"
)
const (
markPrefix = "<mark>"
markSuffix = "</mark>"
)
// allTerms 把快照展开为一组待匹配的词
func allTerms(snaps []contentreviewmod.SensitiveWordSnap) []string {
seen := make(map[string]struct{})
out := make([]string, 0, len(snaps))
for _, s := range snaps {
if s.Word == "" {
continue
}
if _, ok := seen[s.Word]; ok {
continue
}
seen[s.Word] = struct{}{}
out = append(out, s.Word)
}
// 长词优先,避免短词先替换破坏长词的匹配
sort.Slice(out, func(i, j int) bool {
return len(out[i]) > len(out[j])
})
return out
}
// findHits 返回 input 中命中的词(去重,保持长→短顺序)
func findHits(input string, terms []string) []string {
if input == "" || len(terms) == 0 {
return nil
}
hits := make([]string, 0)
seen := make(map[string]struct{})
for _, t := range terms {
if t == "" {
continue
}
if _, ok := seen[t]; ok {
continue
}
if strings.Contains(input, t) {
seen[t] = struct{}{}
hits = append(hits, t)
}
}
return hits
}
// highlight 用 <mark>...</mark> 包裹命中的词
// hits 已按长度降序;为避免再次包裹已 mark 的内容,分段替换
func highlight(input string, hits []string) string {
if input == "" || len(hits) == 0 {
return input
}
result := input
for _, h := range hits {
if h == "" {
continue
}
result = replaceNotInMark(result, h)
}
return result
}
// replaceNotInMark 在 input 中把 term 全部替换为 <mark>term</mark>
// 但跳过已经包在 <mark>...</mark> 内的片段(避免嵌套)
func replaceNotInMark(input, term string) string {
if term == "" {
return input
}
var b strings.Builder
i := 0
for i < len(input) {
// 已经在 mark 块里,整段原样输出
if strings.HasPrefix(input[i:], markPrefix) {
end := strings.Index(input[i:], markSuffix)
if end < 0 {
b.WriteString(input[i:])
return b.String()
}
b.WriteString(input[i : i+end+len(markSuffix)])
i += end + len(markSuffix)
continue
}
if strings.HasPrefix(input[i:], term) {
b.WriteString(markPrefix)
b.WriteString(term)
b.WriteString(markSuffix)
i += len(term)
continue
}
b.WriteByte(input[i])
i++
}
return b.String()
}
// matchAndHighlight 在 input 上一步到位:返回命中词列表 + 高亮后的文本
func matchAndHighlight(input string, terms []string) ([]string, string) {
hits := findHits(input, terms)
if len(hits) == 0 {
return nil, input
}
return hits, highlight(input, hits)
}