web-dev-qa-db-ja.com

Golangで文字列を長さで分割

Golangの文字列を長さで分割する方法を知っている人はいますか?

たとえば、「helloworld」を3文字ごとに分割する場合、理想的には「hel」「low」「orl」「d」の配列を返す必要がありますか?

あるいは、考えられる解決策は、3文字ごとに改行を追加することです。

すべてのアイデアは大歓迎です!

12
Fernando Parra

必ず変換あなたの 文字列 をルーンのスライスに変換してください: " 文字列を文字にスライスします "。

forは自動的にstringruneに変換するため、この場合、最初にstringruneに変換するための追加のコードは必要ありません。

_for i, r := range s {
    fmt.Printf("i%d r %c\n", i, r)
    // every 3 i, do something
}
_

_r[n:n+3]_は、ルーンのスライスである場合に最適に機能します。

インデックスはルーンごとに1増加しますが、バイトごとに複数増加する可能性があります文字列のスライス : "世界":iは0と3になります:文字(ルーン)は複数のバイトで構成できます。


たとえば、_s := "世a界世bcd界efg世"_:12ルーンを考えてみましょう。 (見る play.golang.org

バイトごとに解析しようとすると、インデックスがそれらを超えて増加するため、「3を法とするインデックス」(2、5、8、および11に等しい)の一部を(3文字ごとの単純な分割で)見逃します。値:

_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))を反復処理すると、インデックスによって一度に1つのルーン文字が増加し、正確に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世'
_
18
VonC

最近これを行うための関数も必要でした。 ここでの使用例 を参照してください。

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
}
6
mozey

関数を実装するために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)

}
1
ryan

これは別の例です(試してみることができます ここ ):

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"))
}
1
rinat.io

正規表現を使用した簡単なソリューション

re:= regexp.MustCompile((\S{3}))x:= re.FindAllStringSubmatch( "HelloWorld"、-1)fmt.Println(x)

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

0
rahul