英文:
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 string
s are precisely 100 characters long, the remaining part of the byte array
is padded with 0
s.
If I convert [100]byte
to string
by: string(byteArray[:])
, the tailing 0
s 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
是读取的字节数,你的代码应该像这样:
s := string(byteArray[:n])
要转换整个字符串,可以使用以下代码:
s := string(byteArray[:len(byteArray)])
这等同于:
s := string(byteArray[:])
如果由于某种原因你不知道n
,你可以使用bytes
包来找到它,假设你的输入中没有嵌入空字符。
n := bytes.Index(byteArray[:], []byte{0})
或者如icza指出的,你可以使用下面的代码:
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:
s := string(byteArray[:n])
To convert the full string, this can be used:
s := string(byteArray[:len(byteArray)])
This is equivalent to:
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.
n := bytes.Index(byteArray[:], []byte{0})
Or as icza pointed out, you can use the code below:
n := bytes.IndexByte(byteArray[:], 0)
答案2
得分: 375
使用:
s := string(byteArray[:])
英文:
Use:
s := string(byteArray[:])
答案3
得分: 69
简单的解决方案:
str := fmt.Sprintf("%s", byteArray)
我不确定这个解决方案的性能如何。
英文:
Simplistic solution:
str := fmt.Sprintf("%s", byteArray)
I'm not sure how performant this is though.
答案4
得分: 16
例如,
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
英文:
For example,
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)
}
Output:
C: 100 [97 98 99 0]
Go: 3 abc
答案5
得分: 7
以下代码正在寻找'\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] == '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))
}
0' {
max = mid
} else {
min = mid
}
}
return len(b)
}
func main() {
b := []byte{1, 2, 3, 0, 0, 0}
fmt.Println(FirstZero(b))
}
如果大部分字符串都很短,只需简单地扫描字节数组以寻找零字节可能会更快。
英文:
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:
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] == '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))
}
0' {
max = mid
} else {
min = mid
}
}
return len(b)
}
func main() {
b := []byte{1, 2, 3, 0, 0, 0}
fmt.Println(FirstZero(b))
}
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
使用这个:
bytes.NewBuffer(byteArray).String()
英文:
Use this:
bytes.NewBuffer(byteArray).String()
答案8
得分: 0
仅用于性能调优。
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))
}
英文:
Only use for performance tuning.
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))
}
答案9
得分: 0
虽然性能不是非常高,但唯一可读的解决方案是:
// 通过分隔符分割并选择第一个。
// 这包含了直到空字符的所有字符,但不包括空字符本身。
retByteArray := bytes.Split(byteArray[:], []byte{0})[0]
// 或者
// 如果你想要一个真正的类C字符串,包括空字符
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)
}
一个完整的示例,生成一个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)
}
这将分配一个字节切片的切片。因此,如果频繁或重复使用,请注意性能。
英文:
Though not extremely performant, the only readable solution is:
// 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]
A full example to have a C-style byte array:
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)
}
A full example to have a Go style string excluding the nulls:
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)
}
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
接受一个切片,而不是一个数组。 -
使用切片而不是零填充。
示例:
buf := make([]byte, 100)
n, err := myReader.Read(buf)
if n == 0 && err != nil {
log.Fatal(err)
}
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:
buf := make([]byte, 100)
n, err := myReader.Read(buf)
if n == 0 && err != nil {
log.Fatal(err)
}
consume(buf[:n]) // consume() will see an exact (not padded) slice of read data
答案11
得分: -2
这里有一个选项可以去除空字节:
package main
import "golang.org/x/sys/windows"
func main() {
b := []byte{'M', 'a', 'r', 'c', 'h', 0}
s := windows.ByteSliceToString(b)
println(s == "March")
}
- https://pkg.go.dev/golang.org/x/sys/unix#ByteSliceToString
- https://pkg.go.dev/golang.org/x/sys/windows#ByteSliceToString
英文:
Here is an option that removes the null bytes:
package main
import "golang.org/x/sys/windows"
func main() {
b := []byte{'M', 'a', 'r', 'c', 'h', 0}
s := windows.ByteSliceToString(b)
println(s == "March")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论