web-dev-qa-db-ja.com

0で終わるバイト配列を文字列に変換する方法

大量のstringデータを転送するには、[100]byteを読む必要があります。

すべてのstringの長さが正確に100文字ではないため、byte arrayの残りの部分には0が埋め込まれます。

[100]bytestring(byteArray[:])stringに変換すると、末尾の0^@^@sとして表示されます。

Cではstring0で終わるので、Golangでbyte arraystringにスマートに転送するための最善の方法は何でしょうか。

461
Derrick Zhang

データをバイトスライスに読み込むメソッドは、読み込んだバイト数を返します。その番号を保存してから、それを使って文字列を作成してください。 nは読み込んだバイト数なので、コードは次のようになります。

s := string(byteArray[:n])

何らかの理由でnがない場合は、入力にnull文字が含まれていないと想定して、bytesパッケージを使用してそれを見つけることができます。

n := bytes.Index(byteArray, []byte{0})

またはiczaが指摘したように、あなたは以下のコードを使うことができます:

n := bytes.IndexByte(byteArray, 0)
471
Daniel

どうですか?

s := string(byteArray[:])
363
mattes

単純な解決策:

str := fmt.Sprintf("%s", byteArray)

私はこれがどれほどパフォーマンスがよいかわからない。

59
marcusljx

例えば、

package main

import "fmt"

func CToGoString(c []byte) string {
    n := -1
    for i, b := range c {
        if b == 0 {
            break
        }
        n = i
    }
    return string(c[:n+1])
}

func main() {
    c := [100]byte{'a', 'b', 'c'}
    fmt.Println("C: ", len(c), c[:4])
    g := CToGoString(c[:])
    fmt.Println("Go:", len(g), g)
}

出力:

C:  100 [97 98 99 0]
Go: 3 abc
13
peterSO

次のコードは '\ 0'を探していて、質問の仮定の下では、すべての '\ 0'がすべての '\ 0'に先行するため、配列はソート済みと見なすことができます。配列がデータ内に '\ 0'を含むことができる場合、この仮定は成り立ちません。

二分探索を使用して最初のゼロバイトの位置を見つけ、次にスライスします。

あなたはこのようなゼロバイトを見つけることができます:

package main

import "fmt"

func FirstZero(b []byte) int {
    min, max := 0, len(b)
    for {
        if min + 1 == max { return max }
        mid := (min + max) / 2
        if b[mid] == '\000' {
            max = mid
        } else {
            min = mid
        }
    }
    return len(b)
}
func main() {
    b := []byte{1, 2, 3, 0, 0, 0}
    fmt.Println(FirstZero(b))
}

特にほとんどの文字列が短い場合は、単純にバイト配列をスキャンしてゼロバイトを探す方が速い場合があります。

7
Paul Hankin

配列内のnil以外のバイトの正確な長さがわからない場合は、まずそれをトリミングできます。

文字列(bytes.Trim(arr、 "\ x00"))

3
zach

パフォーマンスチューニングにのみ使用します。

package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func BytesToString(b []byte) string {
    bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
    sh := reflect.StringHeader{bh.Data, bh.Len}
    return *(*string)(unsafe.Pointer(&sh))
}

func StringToBytes(s string) []byte {
    sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    bh := reflect.SliceHeader{sh.Data, sh.Len, 0}
    return *(*[]byte)(unsafe.Pointer(&bh))
}

func main() {
    b := []byte{'b', 'y', 't', 'e'}
    s := BytesToString(b)
    fmt.Println(s)
    b = StringToBytes(s)
    fmt.Println(string(b))
}
2
yuen

どうしてこれじゃないの?

bytes.NewBuffer(byteArray).String()
1

私はパニックになったいくつかの方法を数回試しました:

実行時エラー:スライスは範囲外です。

しかし、これはついにうまくいきました。

string(Data[:])

0
Gaurav Singh
  • 読み取りには配列の代わりにスライスを使用してください。例えば io.Reader は配列ではなくスライスを受け入れます。

  • ゼロパディングの代わりにスライスを使用してください。

例:

buf := make([]byte, 100)
n, err := myReader.Read(buf)
if n == 0 && err != nil {
        log.Fatal(err)
}

consume(buf[:n]) // consume will see exact (not padded) slice of read data
0
zzzz