UTF-8 将 Go 字符串安全截断为少于 N 个字节

问题描述 投票:0回答:1

有时我需要截断字符串以适应特定的字节数。在 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]
}

问题如下:

  1. 这行得通还是有我错过的边缘情况?
  2. 有没有更好、更雄辩的方法来做到这一点,我错过了,或者标准库函数已经做到了这一点?
  3. 为什么这不是
    "unicode/utf8"
    下的标准库函数?似乎只有适当的使用频率和复杂程度才能保证拥有标准库函数。我应该在他们的问题页面中提出吗?
string go utf-8
1个回答
0
投票
  1. 您的实施虽然动机良好,但并不完全正确(例如
    len(UTF8SafeTruncateNBytes("世", 1))
    结果为 3 而不是 0)
  2. 您应该考虑使用现有的优化实现:https://pkg.go.dev/tailscale.com/util/truncate
  3. 将其包含在标准库中的提议不会有什么坏处,但请注意,它可能会因与 https://github.com/golang/go/issues/56885
  4. 类似的原因而被拒绝
© www.soinside.com 2019 - 2024. All rights reserved.