32 lines
1.2 KiB
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 == '\''
|
|
}
|