2 回答
TA贡献1825条经验 获得超6个赞
这是您的算法的改编版,它从前缀的开头和后缀的结尾删除不完整的符文:
func TrimLastIncompleteRune(s string) string {
l := len(s)
for i := 1; i <= l; i++ {
suff := s[l-i : l]
// repeatedly try to decode a rune from the last bytes in string
r, cnt := utf8.DecodeRuneInString(suff)
if r == utf8.RuneError {
continue
}
// if success : return the substring which contains
// this succesfully decoded rune
lgth := l - i + cnt
return s[:lgth]
}
return ""
}
func TrimFirstIncompleteRune(s string) string {
// repeatedly try to decode a rune from the beginning
for i := 0; i < len(s); i++ {
if r, _ := utf8.DecodeRuneInString(s[i:]); r != utf8.RuneError {
// if success : return
return s[i:]
}
}
return ""
}
func shortenStringIDToMaxLength(in string, maxLen int) string {
if len(in) > maxLen {
firstHalf := maxLen / 2
secondHalf := len(in) - (maxLen - firstHalf)
prefix := TrimLastIncompleteRune(in[:firstHalf])
suffix := TrimFirstIncompleteRune(in[secondHalf:])
return prefix + suffix
}
return in
}
play.golang.org 上的链接
此算法仅尝试从选定的前缀和后缀中删除更多字节。
例如,如果事实证明您需要从后缀中删除 3 个字节才能获得有效的符文,则它不会尝试查看是否可以在前缀中添加 3 个字节,以获得更接近maxLen字节的最终结果。
TA贡献1877条经验 获得超1个赞
您可以使用简单的算术来查找start和end使得字符串s[:start]+s[end:]短于您的字节限制。但是您需要确保start和end都是任何 utf-8 序列的第一个字节,以保持序列有效。
UTF-8 的特性是任何给定字节都是序列的第一个字节,只要它的前两位不是 10。
所以你可以写这样的代码(操场: https: //play.golang.org/p/xk_Yo_1wTYc)
package main
import (
"fmt"
)
func truncString(s string, maxLen int) string {
if len(s) <= maxLen {
return s
}
start := (maxLen + 1) / 2
for start > 0 && s[start]>>6 == 0b10 {
start--
}
end := len(s) - (maxLen - start)
for end < len(s) && s[end]>>6 == 0b10 {
end++
}
return s[:start] + s[end:]
}
func main() {
fmt.Println(truncString("this is a test", 5))
fmt.Println(truncString("日本語", 7))
}
无论输入字符串有多长(假设它是有效的 utf-8),这段代码都有一个理想的属性,它需要 O(maxLen) 时间。
- 2 回答
- 0 关注
- 113 浏览
添加回答
举报