单二进制三角色 + Dock 适配器 + Swarm stack 达到可部署态;mgr1 实测订阅经 central-proxy bootstrap,探活 alive=41/52。 Co-authored-by: Cursor <cursoragent@cursor.com>
71 lines
2.3 KiB
Go
71 lines
2.3 KiB
Go
// 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 ®exWrap{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)
|
||
}
|