在Golang中按长度拆分字符串

时间:2014-09-05 12:37:08

标签: string split go string-length

有谁知道如何按长度分割Golang中的字符串?

例如,在每3个字符后拆分“helloworld”,理想情况下它应该返回一个“hel”“low”“orl”“d”数组?

或者,一个可能的解决方案是在每3个字符后追加一个换行符。

非常感谢所有想法!

6 个答案:

答案 0 :(得分:18)

确保 convert 将您的string加入一片符文:见" Slice string into letters"

a := []rune(s)
for i, r := range a {
    fmt.Printf("i%d r %c\n", i, r)
    // every 3 i, do something
}

a[n:n+3]最适合作为一片符文。

每个符文的索引将增加一个,而slice of string中的每个字节可能增加一个以上:"世界":i将为0和3:一个字符(符文)可以由多个字节组成。


例如,考虑s := "世a界世bcd界efg世":12符文。 (参见 play.golang.org

如果你试图逐字节地解析它,你会错过(在每3个字符实现的天真分裂中)一些"索引模3" (等于2,5,8和11),因为索引将增加超过这些值:

for i, r := range s {
    res = res + string(r)
    fmt.Printf("i %d r %c\n", i, r)
    if i > 0 && (i+1)%3 == 0 {
        fmt.Printf("=>(%d) '%v'\n", i, res)
        res = ""
    }
}

输出:

i  0 r 世
i  3 r a   <== miss i==2
i  4 r 界
i  7 r 世  <== miss i==5
i 10 r b  <== miss i==8
i 11 r c  ===============> would print '世a界世bc', not exactly '3 chars'!
i 12 r d
i 13 r 界
i 16 r e  <== miss i==14
i 17 r f  ===============> would print 'd界ef'
i 18 r g
i 19 r 世 <== miss the rest of the string

但是如果你要迭代符文(a := []rune(s)),你会得到你所期望的,因为索引一次会增加一个符文,这样就可以很容易地聚合3个字符:

for i, r := range a {
    res = res + string(r)
    fmt.Printf("i%d r %c\n", i, r)
    if i > 0 && (i+1)%3 == 0 {
        fmt.Printf("=>(%d) '%v'\n", i, res)
        res = ""
    }
}

输出:

i 0 r 世
i 1 r a
i 2 r 界 ===============> would print '世a界'
i 3 r 世
i 4 r b
i 5 r c ===============> would print '世bc'
i 6 r d
i 7 r 界
i 8 r e ===============> would print 'd界e'
i 9 r f
i10 r g
i11 r 世 ===============> would print 'fg世'

答案 1 :(得分:5)

最近还需要一个功能,请参阅example usage here

func SplitSubN(s string, n int) []string {
    sub := ""
    subs := []string{}

    runes := bytes.Runes([]byte(s))
    l := len(runes)
    for i, r := range runes {
        sub = sub + string(r)
        if (i + 1) % n == 0 {
            subs = append(subs, sub)
            sub = ""
        } else if (i + 1) == l {
            subs = append(subs, sub)
        }
    }

    return subs
}

答案 2 :(得分:4)

这里是playground的另一个变体。 就速度和内存而言,它比其他答案效率更高。如果您要在此处运行基准测试,它们就是benchmarks

System.IO.IOException: Unexpected end of Stream, the content may have already been read by another component. 
   at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)

答案 3 :(得分:1)

这是另一个例子(你可以尝试here):

package main

import (
    "fmt"
    "strings"
)

func ChunkString(s string, chunkSize int) []string {
    var chunks []string
    runes := []rune(s)

    if len(runes) == 0 {
        return []string{s}
    }

    for i := 0; i < len(runes); i += chunkSize {
        nn := i + chunkSize
        if nn > len(runes) {
            nn = len(runes)
        }
        chunks = append(chunks, string(runes[i:nn]))
    }
    return chunks
}

func main() {
    fmt.Println(ChunkString("helloworld", 3))
    fmt.Println(strings.Join(ChunkString("helloworld", 3), "\n"))
}

答案 4 :(得分:1)

我尝试了3个版本来实现该功能,名为“ splitByWidthMake”的功能最快。

这些功能会忽略unicode,但只会忽略ascii代码。

package main

import (
    "fmt"
    "strings"
    "time"
    "math"
)

func splitByWidthMake(str string, size int) []string {
    strLength := len(str)
    splitedLength := int(math.Ceil(float64(strLength) / float64(size)))
    splited := make([]string, splitedLength)
    var start, stop int
    for i := 0; i < splitedLength; i += 1 {
        start = i * size
        stop = start + size
        if stop > strLength {
            stop = strLength
        }
        splited[i] = str[start : stop]
    }
    return splited
}



func splitByWidth(str string, size int) []string {
    strLength := len(str)
    var splited []string
    var stop int
    for i := 0; i < strLength; i += size {
        stop = i + size
        if stop > strLength {
            stop = strLength
        }
        splited = append(splited, str[i:stop])
    }
    return splited
}

func splitRecursive(str string, size int) []string {
    if len(str) <= size {
        return []string{str}
    }
    return append([]string{string(str[0:size])}, splitRecursive(str[size:], size)...)
}

func main() {
    /*
    testStrings := []string{
        "hello world",
        "",
        "1",
    }
    */

    testStrings := make([]string, 10)
    for i := range testStrings {
        testStrings[i] = strings.Repeat("#", int(math.Pow(2, float64(i))))
    }

    //fmt.Println(testStrings)

    t1 := time.Now()
    for i := range testStrings {
        _ = splitByWidthMake(testStrings[i], 2)
        //fmt.Println(t)
    }
    elapsed := time.Since(t1)
    fmt.Println("for loop version elapsed: ", elapsed)


    t1 = time.Now()
    for i := range testStrings {
        _ = splitByWidth(testStrings[i], 2)
    }
    elapsed = time.Since(t1)
    fmt.Println("for loop without make version elapsed: ", elapsed)




    t1 = time.Now()
    for i := range testStrings {
        _ = splitRecursive(testStrings[i], 2)
    }
    elapsed = time.Since(t1)
    fmt.Println("recursive version elapsed: ", elapsed)

}

答案 5 :(得分:0)

使用正则表达式的简单解决方案

re:= regexp.MustCompile((\S{3})) x:= re.FindAllStringSubmatch(&#34; HelloWorld&#34;, - 1) fmt.Println(x)的

https://play.golang.org/p/mfmaQlSRkHe