走了LeftStr,RightStr,SubStr

时间:2015-04-02 06:24:15

标签: string go

我相信没有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循环是唯一的方法?

1 个答案:

答案 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)。

  1. 只需使用n个字节。 这可能在符文中间分裂,但是O(1),非常简单,并且在许多情况下,您知道输入仅由单字节符文组成。 例如。 str[:n]

  2. n符文后拆分。 这可能会分裂在角色的中间。这可以很容易地完成,但代价是仅使用string([]rune(str)[:n])进行复制和转换。 您可以使用unicode/utf8包的DecodeRuneInString(和DecodeLastRuneInString)函数来依次获取每个前n个符文的长度,然后返回{{1},从而避免转换和复制(O(n),没有分配)。

  3. 在第n个“边界”之后分裂。 一种方法是使用 norm.NFC.FirstBoundaryInString(str)一再发生 或norm.Iter找到要拆分的字节位置,然后返回str[:sum]

  4. 考虑显示的字符串“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”)。