105 lines
2.1 KiB
Go
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
|
|
}
|