我相信没有LeftStr(str,n)
(最多需要n个第一个字符),RightStr(str,n)
(最多需要n个最后一个字符)和SubStr(str,pos,n)
(在pos之后取n个字符)功能在Go中,所以我试图制作一个
// take at most n first characters
func Left(str string, num int) string {
if num <= 0 {
return ``
}
if num > len(str) {
num = len(str)
}
return str[:num]
}
// take at most last n characters
func Right(str string, num int) string {
if num <= 0 {
return ``
}
max := len(str)
if num > max {
num = max
}
num = max - num
return str[num:]
}
但我相信当字符串包含unicode字符时,这些函数会给出错误的输出。什么是这些功能的最快解决方案,使用for range
循环是唯一的方法?
答案 0 :(得分:2)
如评论中所述, combining characters,修改符文和其他多符文 "characters" 会造成困难。
任何对Go中的Unicode处理感兴趣的人都应该阅读Go Blog文章
"Strings, bytes, runes and characters in Go"
和"Text normalization in Go"。
特别是,后来讨论了golang.org/x/text/unicode/norm
包可以帮助处理其中的一些问题。
您可以考虑从字符串中剔除第一个(或最后一个)“n个字符”的几个级别越来越准确(或越来越多地识别Unicode)。
只需使用n个字节。
这可能在符文中间分裂,但是O(1),非常简单,并且在许多情况下,您知道输入仅由单字节符文组成。
例如。 str[:n]
。
n符文后拆分。
这可能会分裂在角色的中间。这可以很容易地完成,但代价是仅使用string([]rune(str)[:n])
进行复制和转换。
您可以使用unicode/utf8
包的DecodeRuneInString
(和DecodeLastRuneInString
)函数来依次获取每个前n个符文的长度,然后返回{{1},从而避免转换和复制(O(n),没有分配)。
在第n个“边界”之后分裂。
一种方法是使用
norm.NFC.FirstBoundaryInString(str)
一再发生
或norm.Iter
找到要拆分的字节位置,然后返回str[:sum]
。
考虑显示的字符串“cafés”,它可以在Go代码中表示为:“cafés”,“caf \ u00E9s”或“caf \ xc3 \ xa9s”,它们都会产生相同的六个字节。另外它可以表示为“cafe \ u0301s”或“cafe \ xcc \ x81s”,它们都会产生相同的七个字节。
上面的第一个“方法”可能会分为“caf \ xc3”+“\ xa9s”和cafe \ xcc“+”\ x81s“。
第二种可能将它们分成“caf \ u00E9”+“s”(“café”+“s”)和“cafe”+“\ u0301s”(“cafe”+“s”)。
第三个应该将它们分成“caf \ u00E9”+“s”和“cafe \ u0301”+“s”(均显示为“café”+“s”)。