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 == '\'' }