如何将以零结尾的字节数组转换为字符串?

huangapple go评论183阅读模式
英文:

How can I convert a zero-terminated byte array to string?

问题

我需要读取[100]byte来传输一堆string数据。

因为并不是所有的string都恰好是100个字符长,所以byte数组的剩余部分会用0填充。

如果我通过string(byteArray[:])[100]byte转换为string,尾部的0会显示为^@^@

在C中,string会在遇到0时终止,那么在Go中将这个byte数组转换为string的最佳方法是什么?

英文:

I need to read [100]byte to transfer a bunch of string data.

Because not all of the strings are precisely 100 characters long, the remaining part of the byte array is padded with 0s.

If I convert [100]byte to string by: string(byteArray[:]), the tailing 0s are displayed as ^@^@s.

In C, the string will terminate upon 0, so what's the best way to convert this byte array to string in Go?

答案1

得分: 554

读取数据到字节切片的方法会返回读取的字节数。你应该保存这个数字,然后使用它来创建你的字符串。如果n是读取的字节数,你的代码应该像这样:

  1. s := string(byteArray[:n])

要转换整个字符串,可以使用以下代码:

  1. s := string(byteArray[:len(byteArray)])

这等同于:

  1. s := string(byteArray[:])

如果由于某种原因你不知道n,你可以使用bytes包来找到它,假设你的输入中没有嵌入空字符。

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

或者如icza指出的,你可以使用下面的代码:

  1. n := bytes.IndexByte(byteArray[:], 0)
英文:

Methods that read data into byte slices return the number of bytes read. You should save that number and then use it to create your string. If n is the number of bytes read, your code would look like this:

  1. s := string(byteArray[:n])

To convert the full string, this can be used:

  1. s := string(byteArray[:len(byteArray)])

This is equivalent to:

  1. s := string(byteArray[:])

If for some reason you don't know n, you could use the bytes package to find it, assuming your input doesn't have a null character embedded in it.

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

Or as icza pointed out, you can use the code below:

  1. n := bytes.IndexByte(byteArray[:], 0)

答案2

得分: 375

使用:

  1. s := string(byteArray[:])
英文:

Use:

  1. s := string(byteArray[:])

答案3

得分: 69

简单的解决方案:

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

我不确定这个解决方案的性能如何。

英文:

Simplistic solution:

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

I'm not sure how performant this is though.

答案4

得分: 16

例如,

  1. package main
  2. import "fmt"
  3. func CToGoString(c []byte) string {
  4. n := -1
  5. for i, b := range c {
  6. if b == 0 {
  7. break
  8. }
  9. n = i
  10. }
  11. return string(c[:n+1])
  12. }
  13. func main() {
  14. c := [100]byte{'a', 'b', 'c'}
  15. fmt.Println("C: ", len(c), c[:4])
  16. g := CToGoString(c[:])
  17. fmt.Println("Go:", len(g), g)
  18. }

输出:

  1. C: 100 [97 98 99 0]
  2. Go: 3 abc
英文:

For example,

  1. package main
  2. import "fmt"
  3. func CToGoString(c []byte) string {
  4. n := -1
  5. for i, b := range c {
  6. if b == 0 {
  7. break
  8. }
  9. n = i
  10. }
  11. return string(c[:n+1])
  12. }
  13. func main() {
  14. c := [100]byte{'a', 'b', 'c'}
  15. fmt.Println("C: ", len(c), c[:4])
  16. g := CToGoString(c[:])
  17. fmt.Println("Go:", len(g), g)
  18. }

Output:

  1. C: 100 [97 98 99 0]
  2. Go: 3 abc

答案5

得分: 7

以下代码正在寻找'\0',根据问题的假设,数组可以被认为是已排序的,因为所有非'\0'都在所有'\0'之前。如果数组中包含数据中的'\0',这个假设将不成立。

使用二分查找找到第一个零字节的位置,然后进行切片。

你可以像这样找到零字节:

  1. package main
  2. import "fmt"
  3. func FirstZero(b []byte) int {
  4. min, max := 0, len(b)
  5. for {
  6. if min + 1 == max { return max }
  7. mid := (min + max) / 2
  8. if b[mid] == '
    package main
  9. import "fmt"
  10. func FirstZero(b []byte) int {
  11. min, max := 0, len(b)
  12. for {
  13. if min + 1 == max { return max }
  14. mid := (min + max) / 2
  15. if b[mid] == '\000' {
  16. max = mid
  17. } else {
  18. min = mid
  19. }
  20. }
  21. return len(b)
  22. }
  23. func main() {
  24. b := []byte{1, 2, 3, 0, 0, 0}
  25. fmt.Println(FirstZero(b))
  26. }
  27. 0' {
  28. max = mid
  29. } else {
  30. min = mid
  31. }
  32. }
  33. return len(b)
  34. }
  35. func main() {
  36. b := []byte{1, 2, 3, 0, 0, 0}
  37. fmt.Println(FirstZero(b))
  38. }

如果大部分字符串都很短,只需简单地扫描字节数组以寻找零字节可能会更快。

英文:

The following code is looking for '\0', and under the assumptions of the question the array can be considered sorted since all non-'\0' precede all '\0'. This assumption won't hold if the array can contain '\0' within the data.

Find the location of the first zero-byte using a binary search, then slice.

You can find the zero-byte like this:

  1. package main
  2. import "fmt"
  3. func FirstZero(b []byte) int {
  4. min, max := 0, len(b)
  5. for {
  6. if min + 1 == max { return max }
  7. mid := (min + max) / 2
  8. if b[mid] == '
    package main
  9. import "fmt"
  10. func FirstZero(b []byte) int {
  11. min, max := 0, len(b)
  12. for {
  13. if min + 1 == max { return max }
  14. mid := (min + max) / 2
  15. if b[mid] == '\000' {
  16. max = mid
  17. } else {
  18. min = mid
  19. }
  20. }
  21. return len(b)
  22. }
  23. func main() {
  24. b := []byte{1, 2, 3, 0, 0, 0}
  25. fmt.Println(FirstZero(b))
  26. }
  27. 0' {
  28. max = mid
  29. } else {
  30. min = mid
  31. }
  32. }
  33. return len(b)
  34. }
  35. func main() {
  36. b := []byte{1, 2, 3, 0, 0, 0}
  37. fmt.Println(FirstZero(b))
  38. }

It may be faster just to naively scan the byte array looking for the zero-byte, especially if most of your strings are short.

答案6

得分: 2

当你不知道数组中非nil字节的确切长度时,你可以先修剪它:

string(bytes.Trim(arr, "\x00"))

英文:

When you do not know the exact length of non-nil bytes in the array, you can trim it first:

> string(bytes.Trim(arr, "\x00"))

答案7

得分: 1

使用这个:

  1. bytes.NewBuffer(byteArray).String()
英文:

Use this:

  1. bytes.NewBuffer(byteArray).String()

答案8

得分: 0

仅用于性能调优。

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. "unsafe"
  6. )
  7. func BytesToString(b []byte) string {
  8. return *(*string)(unsafe.Pointer(&b))
  9. }
  10. func StringToBytes(s string) []byte {
  11. return *(*[]byte)(unsafe.Pointer(&s))
  12. }
  13. func main() {
  14. b := []byte{'b', 'y', 't', 'e'}
  15. s := BytesToString(b)
  16. fmt.Println(s)
  17. b = StringToBytes(s)
  18. fmt.Println(string(b))
  19. }
英文:

Only use for performance tuning.

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. "unsafe"
  6. )
  7. func BytesToString(b []byte) string {
  8. return *(*string)(unsafe.Pointer(&b))
  9. }
  10. func StringToBytes(s string) []byte {
  11. return *(*[]byte)(unsafe.Pointer(&s))
  12. }
  13. func main() {
  14. b := []byte{'b', 'y', 't', 'e'}
  15. s := BytesToString(b)
  16. fmt.Println(s)
  17. b = StringToBytes(s)
  18. fmt.Println(string(b))
  19. }

答案9

得分: 0

虽然性能不是非常高,但唯一可读的解决方案是:

  1. // 通过分隔符分割并选择第一个。
  2. // 这包含了直到空字符的所有字符,但不包括空字符本身。
  3. retByteArray := bytes.Split(byteArray[:], []byte{0})[0]
  4. // 或者
  5. // 如果你想要一个真正的类C字符串,包括空字符
  6. retByteArray := bytes.SplitAfter(byteArray[:], []byte{0})[0]

一个完整的示例,生成一个C风格的字节数组:

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. )
  6. func main() {
  7. var byteArray = [6]byte{97,98,0,100,0,99}
  8. cStyleString := bytes.SplitAfter(byteArray[:], []byte{0})[0]
  9. fmt.Println(cStyleString)
  10. }

一个完整的示例,生成一个Go风格的字符串,不包括空字符:

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. )
  6. func main() {
  7. var byteArray = [6]byte{97, 98, 0, 100, 0, 99}
  8. goStyleString := string(bytes.Split(byteArray[:], []byte{0})[0])
  9. fmt.Println(goStyleString)
  10. }

这将分配一个字节切片的切片。因此,如果频繁或重复使用,请注意性能。

英文:

Though not extremely performant, the only readable solution is:

  1. // Split by separator and pick the first one.
  2. // This has all the characters till null, excluding null itself.
  3. retByteArray := bytes.Split(byteArray[:], []byte{0}) [0]
  4. // OR
  5. // If you want a true C-like string, including the null character
  6. retByteArray := bytes.SplitAfter(byteArray[:], []byte{0}) [0]

A full example to have a C-style byte array:

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. )
  6. func main() {
  7. var byteArray = [6]byte{97,98,0,100,0,99}
  8. cStyleString := bytes.SplitAfter(byteArray[:], []byte{0}) [0]
  9. fmt.Println(cStyleString)
  10. }

A full example to have a Go style string excluding the nulls:

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. )
  6. func main() {
  7. var byteArray = [6]byte{97, 98, 0, 100, 0, 99}
  8. goStyleString := string(bytes.Split(byteArray[:], []byte{0}) [0])
  9. fmt.Println(goStyleString)
  10. }

This allocates a slice of slice of bytes. So keep an eye on performance if it is used heavily or repeatedly.

答案10

得分: -1

  • 使用切片而不是数组进行读取。例如,io.Reader接受一个切片,而不是一个数组。

  • 使用切片而不是零填充。

示例:

  1. buf := make([]byte, 100)
  2. n, err := myReader.Read(buf)
  3. if n == 0 && err != nil {
  4. log.Fatal(err)
  5. }
  6. consume(buf[:n]) // consume()将看到一个精确(非填充)的读取数据切片
英文:
  • Use slices instead of arrays for reading. For example, io.Reader accepts a slice, not an array.

  • Use slicing instead of zero padding.

Example:

  1. buf := make([]byte, 100)
  2. n, err := myReader.Read(buf)
  3. if n == 0 && err != nil {
  4. log.Fatal(err)
  5. }
  6. consume(buf[:n]) // consume() will see an exact (not padded) slice of read data

答案11

得分: -2

这里有一个选项可以去除空字节:

  1. package main
  2. import "golang.org/x/sys/windows"
  3. func main() {
  4. b := []byte{'M', 'a', 'r', 'c', 'h', 0}
  5. s := windows.ByteSliceToString(b)
  6. println(s == "March")
  7. }
英文:

Here is an option that removes the null bytes:

  1. package main
  2. import "golang.org/x/sys/windows"
  3. func main() {
  4. b := []byte{'M', 'a', 'r', 'c', 'h', 0}
  5. s := windows.ByteSliceToString(b)
  6. println(s == "March")
  7. }

huangapple
  • 本文由 发表于 2013年1月9日 15:19:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/14230145.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定