textmachine/backend/internal/text/enclosure.go

32 lines
1.2 KiB
Go

package text
import (
"strings"
"unicode"
)
// TrimEnclosure strips MATCHED enclosing punctuation from a surface, repeatedly. The ends are classified
// by Unicode category (Ps/Pi open, Pe/Pf close) plus the two ASCII quotes, which are Po and invisible to
// those categories — so no table of any language's quotation marks is held here.
//
// Requiring BOTH ends to pair keeps it from mangling a surface that merely touches punctuation, and an
// empty pair is returned as-is: a key must never be trimmed to nothing.
//
// NOT part of the normalization artifact (norm.go / NormVersion): it is applied by one consumer to one
// class of string (a surface a model wrote), and folding it into NormalizeSourceKey would re-verdict every
// match the bank ever made. TestNormVersionUnmovedByEnclosureTrim pins that separation.
func TrimEnclosure(s string) string {
rs := []rune(s)
for len(rs) >= 3 && isOpeningMark(rs[0]) && isClosingMark(rs[len(rs)-1]) {
rs = rs[1 : len(rs)-1]
}
return strings.TrimSpace(string(rs))
}
func isOpeningMark(r rune) bool {
return unicode.Is(unicode.Ps, r) || unicode.Is(unicode.Pi, r) || r == '"' || r == '\''
}
func isClosingMark(r rune) bool {
return unicode.Is(unicode.Pe, r) || unicode.Is(unicode.Pf, r) || r == '"' || r == '\''
}