Files
Memoh/internal/textutil/truncate.go
BBQ 3739def43f fix(text): avoid breaking UTF-8 during truncation
Use rune-aware truncation for user-facing text and log previews so multibyte content is not corrupted in memory context, Telegram messages, or diagnostics.
2026-03-09 12:43:57 +08:00

53 lines
1.2 KiB
Go

package textutil
import "unicode/utf8"
// TruncateRunes returns s truncated to at most maxRunes Unicode code points.
func TruncateRunes(s string, maxRunes int) string {
if maxRunes <= 0 || s == "" {
return ""
}
cut, truncated := byteIndexAfterRunes(s, maxRunes)
if !truncated {
return s
}
return s[:cut]
}
// TruncateRunesWithSuffix returns s truncated to at most maxRunes Unicode code
// points, appending suffix when truncation occurs.
func TruncateRunesWithSuffix(s string, maxRunes int, suffix string) string {
if maxRunes <= 0 || s == "" {
return ""
}
if _, truncated := byteIndexAfterRunes(s, maxRunes); !truncated {
return s
}
if suffix == "" {
return TruncateRunes(s, maxRunes)
}
suffixRunes := utf8.RuneCountInString(suffix)
if suffixRunes >= maxRunes {
return TruncateRunes(s, maxRunes)
}
cut, truncated := byteIndexAfterRunes(s, maxRunes-suffixRunes)
if !truncated {
return s
}
return s[:cut] + suffix
}
func byteIndexAfterRunes(s string, maxRunes int) (int, bool) {
if maxRunes <= 0 || s == "" {
return 0, len(s) > 0
}
count := 0
for i := range s {
if count == maxRunes {
return i, true
}
count++
}
return len(s), false
}