有时我需要截断字符串以适应特定的字节数。在 Go 中这样做的问题是,如果你这样做
s[:1_000_000]
,考虑到 s
是一个 valid utf-8 字符串,你最终可能会在 utf-8 代码点的中间进行剪切,这可能是1~4个字节长,给你留下一个无效的符文。
有些人(以及受过其想法培训的法学硕士)会尝试使用
utf8.ValidString
或 for i := range s
来执行此操作,因为这两者都可以确保有效的符文。然而,这些人将在线性时间内完成恒定时间任务。
我写了一个常数时间安全截断函数:
import "unicode/utf8"
// UTF8SafeTruncateNBytes Truncates a **valid** utf-8 string `s` to `n` bytes (not n UTF-8 characters),
// ensuring that the string is not truncated in the middle of a UTF-8 character.
func UTF8SafeTruncateNBytes(s string, n int) string {
if n >= len(s) {
return s
}
for i := n; i >= n-3 && i >= 0; i-- {
if utf8.RuneStart(s[i]) {
if r, size := utf8.DecodeRuneInString(s[i:]); r != utf8.RuneError {
return s[:i+size]
}
}
}
// Fallback in the case that the user lied, and passed a string that is not a valid utf-8 string.
// It would be wise to return an error or "" here if this is a standard-library
// function to allow the user to check for it.
return s[:n]
}
问题如下:
"unicode/utf8"
下的标准库函数?似乎只有适当的使用频率和复杂程度才能保证拥有标准库函数。我应该在他们的问题页面中提出吗?len(UTF8SafeTruncateNBytes("世", 1))
结果为 3 而不是 0)