spark-server/internal/pkg/sensitive/replace.go
2026-09-29 16:37:36 +08:00

105 lines
2.1 KiB
Go

package sensitive
import "sort"
// ByteInterval is a span in the original UTF-8 text.
type ByteInterval struct {
From int
To int
}
// IntervalsFromMatches maps normalized matches back to original byte intervals.
func IntervalsFromMatches(idx *Index, matches []Match) ([]ByteInterval, bool) {
if idx == nil || len(matches) == 0 {
return nil, true
}
intervals := make([]ByteInterval, 0, len(matches))
for i := range matches {
m := matches[i]
if m.Start < 0 || m.End <= m.Start || m.End > len(idx.OrigFrom) {
return nil, false
}
last := m.End - 1
intervals = append(intervals, ByteInterval{
From: idx.OrigFrom[m.Start],
To: idx.OrigTo[last],
})
}
return mergeIntervals(intervals), true
}
func mergeIntervals(in []ByteInterval) []ByteInterval {
if len(in) == 0 {
return nil
}
sort.Slice(in, func(i, j int) bool { return in[i].From < in[j].From })
out := []ByteInterval{in[0]}
for i := 1; i < len(in); i++ {
last := &out[len(out)-1]
cur := in[i]
if cur.From <= last.To {
if cur.To > last.To {
last.To = cur.To
}
continue
}
out = append(out, cur)
}
return out
}
// Mask replaces each interval with repl (default "***").
func Mask(orig []byte, intervals []ByteInterval, repl string) string {
if len(intervals) == 0 {
return string(orig)
}
if repl == "" {
repl = "***"
}
var b []byte
pos := 0
for _, iv := range intervals {
if iv.From < pos || iv.To < iv.From || iv.To > len(orig) {
return string(orig)
}
b = append(b, orig[pos:iv.From]...)
b = append(b, repl...)
pos = iv.To
}
b = append(b, orig[pos:]...)
return string(b)
}
// Excerpt returns a short slice of orig around [from,to).
func Excerpt(orig []byte, from, to int, maxLen int) string {
if maxLen <= 0 {
maxLen = 128
}
if from < 0 {
from = 0
}
if to > len(orig) {
to = len(orig)
}
if from >= to {
return ""
}
const pad = 24
start := from - pad
if start < 0 {
start = 0
}
end := to + pad
if end > len(orig) {
end = len(orig)
}
s := string(orig[start:end])
if len(s) > maxLen {
if maxLen <= 3 {
return s[:maxLen]
}
return s[:maxLen-3] + "..."
}
return s
}