onesvm-browser-server/server/internal/safetyscan/normalize.go
chii eb972dfa93 feat: 落地 browser-server 控制面并打通 mgr1 海外订阅
单二进制三角色 + Dock 适配器 + Swarm stack 达到可部署态;mgr1 实测订阅经 central-proxy bootstrap,探活 alive=41/52。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 15:05:12 +08:00

71 lines
2.3 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.

// normalize.go:归一化与正则封装(safetyscan 内部实现细节)。
package safetyscan
import (
"regexp"
"strings"
"unicode"
"golang.org/x/text/unicode/norm"
)
// regexWrap 正则包装(编译后只读)。
type regexWrap struct {
re *regexp.Regexp
pattern string
}
// compile 编译正则。
func compile(pattern string) (*regexWrap, error) {
re, err := regexp.Compile(pattern)
if err != nil {
return nil, err
}
return &regexWrap{re: re, pattern: pattern}, nil
}
func (w *regexWrap) matchString(s string) bool { return w.re.MatchString(s) }
func (w *regexWrap) replaceAll(s, repl string) string { return w.re.ReplaceAllString(s, repl) }
// replaceGroup 捕获组替换:保留捕获组前后边界字符,仅把组内容替换为 repl。
func (w *regexWrap) replaceGroup(s string, _groupExpr, repl string) string {
var b strings.Builder
last := 0
for _, loc := range w.re.FindAllStringSubmatchIndex(s, -1) {
// loc = [整起,整止, 组1起,组1止, 组2起,组2止, ...];尾边界组(如 [^0-9]|$)
// 是第二个捕获组,可能匹配空串(索引为 -1),需逐项判空。
if len(loc) < 4 || loc[0] < 0 || loc[2] < 0 || loc[3] < 0 {
continue
}
b.WriteString(s[last:loc[0]]) // 上一匹配结束到本匹配开始
b.WriteString(s[loc[0]:loc[2]]) // 组 1 前的边界字符
b.WriteString(repl) // 组 1 内容替换
if len(loc) >= 6 && loc[4] >= 0 && loc[5] >= 0 && loc[4] < loc[5] {
b.WriteString(s[loc[4]:loc[5]]) // 组 2(尾边界字符)
}
last = loc[1]
}
if last == 0 {
return s
}
b.WriteString(s[last:])
return b.String()
}
func (w *regexWrap) count(s string) int { return len(w.re.FindAllString(s, -1)) }
// normalize NFKC 归一 + 小写 + 全角折叠(design §5.4:NFKC+同形字归一)。
func normalize(s string) string {
s = norm.NFKC.String(s) // 全角→半角、兼容分解
s = strings.ToLower(s)
// 常见混淆字符折叠(样例集,真实同形字表由合规方扩充)
const from = ",。:;!?()「」"
const to = ",.:;!()?()\"\""
runes := []rune(s)
for i, r := range runes {
if idx := strings.IndexRune(from, r); idx >= 0 && idx < len(to) {
runes[i] = rune(to[idx])
}
}
_ = unicode.ToLower // 保留导入位(小写已统一走 strings.ToLower)
return string(runes)
}