string - 在 golang 中正确拆分符文
问题描述
我想知道是否有一种简单的方法,例如处理代码点/符文的众所周知的函数,从符文片的中间取出一块而不会弄乱它,或者是否都需要自己编码才能下来等于或小于最大字节数。
具体来说,我要做的是将字符串传递给函数,将其转换为符文,以便我可以尊重代码点,如果切片长于某些最大字节,则从符文中心移除足够的符文以获得字节到必要的。
如果字符串只是单字节字符并且处理如下:这是简单的数学运算:
func shortenStringIDToMaxLength(in string, maxLen int) string {
if len(in) > maxLen {
excess := len(in) - maxLen
start := maxLen/2 - excess/2
return in[:start] + in[start+excess:]
}
return in
}
但是在一个可变字符宽度的字节字符串中,它要么需要更多的编码循环,要么会有很好的函数来简化它。有没有人有关于如何最好地用符文处理这种事情的代码示例?
这里的想法是字符串将进入的 DB 字段具有固定的最大字节长度,而不是代码点,因此需要一些从符文到最大字节的算法。从字符串中间取字符的原因只是这个特定程序的需要。
谢谢!
编辑:
一旦我发现范围运算符尊重字符串上的符文,这变得很容易只使用我发现的字符串,因为下面的答案很好。在这种情况下,我不必担心字符串是格式良好的 UTF 格式,但如果我这样做了,我现在知道 UTF 模块,谢谢!
这就是我最终得到的结果:
package main
import (
"fmt"
)
func ShortenStringIDToMaxLength(in string, maxLen int) string {
if maxLen < 1 {
// Panic/log whatever is your error system of choice.
}
bytes := len(in)
if bytes > maxLen {
excess := bytes - maxLen
lPos := bytes/2 - excess/2
lastPos := 0
for pos, _ := range in {
if pos > lPos {
lPos = lastPos
break
}
lastPos = pos
}
rPos := lPos + excess
for pos, _ := range in[lPos:] {
if pos >= excess {
rPos = pos
break
}
}
return in[:lPos] + in[lPos+rPos:]
}
return in
}
func main() {
out := ShortenStringIDToMaxLength(`123456789 123456789`, 5)
fmt.Println(out, len(out))
}
解决方案
您可以使用简单的算术来查找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) 时间。
推荐阅读
- java - Flink Job Cluster vs Session Cluster - 部署和配置
- regex - 我正在尝试删除除电子邮件以外的所有内容,但我得到了相反的结果
- julia - 直接从 julia 调用 BLAS 的问题(在库 libopenblas64_ 中找不到函数:zgemm_64_)
- typescript - 如何仅在 WebStorm 和 Visual Studio 开启时运行自动热键脚本?
- node.js - 写入createReadStream内容创建的文件与原始数据不匹配
- javascript - 使用 Jquery 在日期中添加天数
- r - Matchit 包中的警告(“Glm.fit:出现数字 0 或 1 的拟合概率”)如何处理?
- twilio - 不欺骗电话
- python - Python Falcon 和 Axios:无法允许 CORS
- r - R for 循环结果