如何将零终止的字节数组转换为字符串?

时间:2013-01-09 07:19:48

标签: go

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

由于并非所有string的长度都恰好为100个字符,因此byte array的剩余部分会填充0个。

如果我通过[100]bytestring转移到string(byteArray[:]),则跟踪0会显示为^@^@ s。

在C中,string将在0后终止,因此我想知道在Golang中将byte array智能转移到string的最佳方法是什么。

15 个答案:

答案 0 :(得分:473)

将数据读入字节片的方法返回读取的字节数。您应该保存该号码,然后使用它来创建您的字符串。 n是读取的字节数,您的代码如下所示:

s := string(byteArray[:n])

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

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

或者icza指出,您可以使用以下代码:

n := bytes.IndexByte(byteArray, 0)

答案 1 :(得分:365)

怎么样?

s := string(byteArray[:])

答案 2 :(得分:59)

简单的解决方案:

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

我不确定这是多么高效。

答案 3 :(得分:13)

例如,

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

答案 4 :(得分: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] == '\000' {
            max = mid
        } else {
            min = mid
        }
    }
    return len(b)
}
func main() {
    b := []byte{1, 2, 3, 0, 0, 0}
    fmt.Println(FirstZero(b))
}

天真地扫描字节数组寻找零字节可能更快,特别是如果你的大多数字符串都很短。

答案 5 :(得分:3)

Olny用于性能调整。

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))
}

答案 6 :(得分:3)

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

  

string(bytes.Trim(arr,“\ x00”))

答案 7 :(得分:1)

为什么不呢?

bytes.NewBuffer(byteArray).String()

答案 8 :(得分:0)

  • 使用切片而不是数组进行读取。例如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

答案 9 :(得分:0)

我几次尝试了几种方法,我感到恐慌:

  

运行时错误:切片范围超出范围。

但这终于奏效了。

string(Data[:])

答案 10 :(得分:0)

这是将字节数组压缩为字符串的代码

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
}

答案 11 :(得分:0)

虽然性能不是很出色,但是唯一可读的解决方案是

  //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)
}

完整示例,其中包含一个go样式字符串,但不包括null:

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)
}

这将分配一片字节的片段。因此,如果频繁使用或反复使用,请留意性能。

答案 12 :(得分:-1)

这是更快的方法:

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

答案 13 :(得分:-1)

这是一个删除空字节的选项:

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")
}

答案 14 :(得分:-8)

我使用递归解决方案。

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, ""))
}
相关问题