Quelle est la meilleure façon de convertir un tableau d'octets en chaîne?
J'ai besoin de lire [100]byte
pour transférer un tas de données string
.
Parce que tout le string
n'est pas précisément long de 100, la partie restante du byte array
est rembourrée avec 0
S.
Si je tansfer [100]byte
à string
par: string(byteArray[:])
, la filature 0
s sont affichés sous la forme ^@^@
s.
En C, le {[1] } se terminera sur 0
, donc je me demande Quel est le meilleur moyen de transférer intelligemment byte array
à string
.
11 réponses
Les méthodes qui lisent des données en tranches d'octets renvoient le nombre d'octets lus. Vous devez enregistrer le nombre et l'utiliser pour créer votre chaîne. n
étant le nombre d'octets lus, votre code ressemblerait à ceci:
s := string(byteArray[:n])
Si pour une raison quelconque vous n'avez pas n
, vous pouvez utiliser le paquet bytes pour le trouver, en supposant que votre entrée n'a pas de caractère nul.
n := bytes.Index(byteArray, []byte{0})
Ou comme icza l'a souligné, vous pouvez utiliser le code ci-dessous:
n := bytes.IndexByte(byteArray, 0)
Solution Simpliste:
str := fmt.Sprintf("%s", byteArray)
Je ne sais pas à quel point c'est performant.
Par exemple
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)
}
Sortie:
C: 100 [97 98 99 0]
Go: 3 abc
Le code suivant Recherche '\ 0', et sous les hypothèses de la question, le tableau peut être considéré comme trié puisque tous les non - '\0 'précèdent tous les '\ 0'. Cette hypothèse ne tiendra pas si le tableau peut contenir '\ 0 ' dans les données.
Trouvez l'emplacement du premier octet zéro à l'aide d'une recherche binaire, puis découpez.
, Vous pouvez trouver le zéro octet comme ceci:
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))
}
Il peut être plus rapide de scanner naïvement le tableau d'octets à la recherche du zéro octet, surtout si la plupart de vos les cordes sont courtes.
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))
}
J'ai essayé quelques méthodes quelques fois j'ai eu la panique:
Erreur D'exécution: découper les limites hors de portée.
Mais cela a finalement fonctionné.
string(Data[:])
Lorsque vous ne connaissez pas la longueur exacte des octets non nuls dans le tableau, vous pouvez le couper en premier:
Chaîne (octets.Garniture(arr, "\x00"))
Utilisez des tranches au lieu de tableaux pour la lecture. par exemple
io.Reader
accepte une tranche, pas un tableau.Utilisez le tranchage au lieu de zéro remplissage.
Exemple:
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
I quand avec une solution récursive.
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, ""))
}