回答:
データをバイトスライスに読み取るメソッドは、読み取ったバイト数を返します。その数を保存し、それを使用して文字列を作成する必要n
があります。が読み取ったバイト数の場合、コードは次のようになります。
s := string(byteArray[:n])
完全な文字列を変換するには、これを使用できます。
s := string(byteArray[:len(byteArray)])
これは次と同等です。
s := string(byteArray)
何らかの理由でわからないn
場合は、bytes
パッケージを使用してパッケージを検索できます。入力にnull文字が埋め込まれていないと想定します。
n := bytes.Index(byteArray, []byte{0})
または、iczaが指摘したように、以下のコードを使用できます。
n := bytes.IndexByte(byteArray, 0)
どう?
s := string(byteArray[:])
string(byteArray[:])
含まれていると具体的に記載されています^@
string(byteArray)
ますか?なぜアレイをコピーする必要があるの[:]
ですか?
[:]
ません。バイト配列の場合は追加します。
例えば、
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
次のコードは '\ 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))
}
特にほとんどの文字列が短い場合は、単純にバイト配列をスキャンしてゼロバイトを探す方が速い場合があります。
[]byte{0}
。この場合にFirstZero()
返すべき0
スライス結果であろうときに""
、その代わりにそれは返し1
およびスライス結果"\x00"
。
配列のnil以外のバイトの正確な長さがわからない場合は、最初に切り取ります。
string(bytes.Trim(arr、 "\ x00"))
bytes.Trim
配列ではなくスライスをarr[:]
取得します(arrが実際にaである場合は[100]byte
、質問のとおりに必要です)。b)bytes.Trim
ここで使用するのは間違った関数です。このような入力の場合[]byte{0,0,'a','b','c',0,'d',0}
、「」ではなく「abc \ x00d」が返されます。c)を使用する正しい答えがすでにありbytes.IndexByte
ます。これは、最初のゼロバイトを見つけるための最良の方法です。
なぜこれではないのですか?
bytes.NewBuffer(byteArray).String()
byteArray[:]
以来bytes.NewBuffer
とります[]byte
。b)配列には、処理しない末尾のゼロが含まれているとの質問。c)代わりに変数が[]byte
(行がコンパイルされる唯一の方法)である場合、行は実行の遅い方法ですstring(v)
。
パフォーマンス調整にのみ使用します。
package main
import (
"fmt"
"reflect"
"unsafe"
)
func BytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func StringToBytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&s))
}
func main() {
b := []byte{'b', 'y', 't', 'e'}
s := BytesToString(b)
fmt.Println(s)
b = StringToBytes(s)
fmt.Println(string(b))
}
string
後でバイトスライスが変更された場合に深刻な影響が生じる可能性があります。string
Goの値は、不変であると定義されており、Goランタイム全体とライブラリがその上で構築されます。このパスをたどると、最も神秘的なバグとランタイムエラーの真ん中にテレポートします。
読み取りには、配列の代わりにスライスを使用してください。たとえば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
s := a[:n]
またはs := string(a[:n])
文字列が必要な場合は、バイト配列をスライスします。n
直接利用できない場合は、たとえば、ダニエルが示唆するように、バッファ(配列)内の特定/ゼロのバイトを探すことによって、計算する必要があります。
私はいくつかの方法を数回試しましたが、パニックになりました:
実行時エラー:スライスの境界が範囲外です。
しかし、これでようやくうまくいきました。
string(Data[:])
非常に高性能ではありませんが、唯一の読みやすいソリューションは
//split by separator and pick the first one.
//This has all the characters till null excluding null itself.
retByteArray := bytes.Split(byteArray[:], []byte{0}) [0]
// OR
//If you want a true C-like string including the null character
retByteArray := bytes.SplitAfter(byteArray[:], []byte{0}) [0]
Cスタイルのバイト配列の完全な例:
package main
import (
"bytes"
"fmt"
)
func main() {
var byteArray = [6]byte{97,98,0,100,0,99}
cStyleString := bytes.SplitAfter(byteArray[:], []byte{0}) [0]
fmt.Println(cStyleString)
}
nullを除いたgoスタイル文字列の完全な例:
package main
import (
"bytes"
"fmt"
)
func main() {
var byteArray = [6]byte{97,98,0,100,0,99}
goStyleString := string( bytes.Split(byteArray[:], []byte{0}) [0] )
fmt.Println(goStyleString)
}
これにより、バイトのスライスのスライスが割り当てられます。したがって、頻繁にまたは繰り返し使用する場合は、パフォーマンスに注意してください。
バイト配列を文字列に圧縮するコードは次のとおりです
package main
import (
"fmt"
)
func main() {
byteArr := [100]byte{'b', 'y', 't', 'e', 's'}
firstHalf := ToString(byteArr)
fmt.Println("Bytes to str", string(firstHalf))
}
func ToString(byteArr [100]byte) []byte {
arrLen := len(byteArr)
firstHalf := byteArr[:arrLen/2]
secHalf := byteArr[arrLen/2:]
for {
// if the first element is 0 in secondHalf discard second half
if len(secHalf) != 0 && secHalf[0] == 0 {
arrLen = len(firstHalf)
secHalf = firstHalf[arrLen/2:]
firstHalf = firstHalf[:arrLen/2]
continue
} else {
for idx := 0; len(secHalf) > idx && secHalf[idx] != 0; idx++ {
firstHalf = append(firstHalf, secHalf[idx])
}
}
break
}
return firstHalf
}
これはより速い方法です:
resp, _ := http.Get("https://www.something.com/something.xml")
bytes, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close()
fmt.Println(string(bytes)) //just convert with string() function
fmt
はfmt.Printf("%s", bytes)
、を使用するよりも高速ですstring(bytes)
)。
再帰的な解決策があるとき。
func CToGoString(c []byte, acc string) string {
if len(c) == 0 {
return acc
} else {
head := c[0]
tail := c[1:]
return CToGoString(tail, acc + fmt.Sprintf("%c", head))
}
}
func main() {
b := []byte{some char bytes}
fmt.Println(CToGoString(b, ""))
}
fmt.Println(CToGoString([]byte("ctogo\x00\x00"), "") == "ctogo")
印刷する必要がありtrue
、それが印刷さfalse
。
[100]byte
が、[]byte
、および取り除くしない'\x00'
バイトを。その速度(入力に依存します)は、受け入れられた回答の速度と比較して、数桁遅くなります。
^@
はは表示されませんが、ターミナルなどでテストすると表示されます。これは、Goが0len(string(bytes))
を検出したときにバイト配列の文字列への変換を停止しないためです。この例では、1ではなく5です。これは、文字列が完全に(ゼロで)印刷されているかどうか、出力関数によって異なりますか否か。