簡體   English   中英

如何將字節緩沖區中以 null 結尾的字符串轉換為 Go 中的字符串?

[英]How can I convert a null-terminated string in a byte buffer to a string in Go?

這個:

label := string([]byte{97, 98, 99, 0, 0, 0, 0})
fmt.Printf("%s\n", label)

這樣做( ^@是空字節):

go run test.go 
abc^@^@^@

請注意,第一個答案僅適用於在null終止符后僅運行零的字符串; 但是,一個正確的C風格的以null結尾的字符串在第一個\\0結尾,即使它后面跟着垃圾。 例如, []byte{97,98,99,0,99,99,0}應解析為abc ,而不是abc^@cc

要正確解析它,請使用string.Index ,如下所示,找到第一個 \\0並使用它來切片原始字節切片:

package main

import (
    "fmt"
    "strings"
)

func main() {
    label := []byte{97,98,99,0,99,99,0}
    nullIndex := strings.Index(string(label), "\x00")
    if (nullIndex < 0) {
        fmt.Println("Buffer did not hold a null-terminated string")
        os.Exit(1)
    }
    fmt.Println(string(label[:nullIndex]))
}

編輯:將縮短版本打印為[]byte而不是string 感謝@serbaut的捕獲。

編輯2:沒有處理沒有空終止符的緩沖區的錯誤情況。 感謝@snap的捕獲。

在Go的syscall包中隱藏了這個函數,它找到第一個空字節([] byte {0})並返回長度。 我假設它被稱為C-Length的clen。

對不起,我對這個答案遲了一年,但我覺得它比其他兩個簡單得多(沒有不必要的進口等)

func clen(n []byte) int {
    for i := 0; i < len(n); i++ {
        if n[i] == 0 {
            return i
        }
    }
    return len(n)
}

所以,

label := []byte{97, 98, 99, 0, 0, 0, 0}
s := label[:clen(label)]
fmt.Println(string(s))

^所說的是將s設置為從開頭到clen(label)索引的label的字節切片。

結果將是abc ,長度為3。

使用strings包。

package main

import (
    "fmt"
    "strings"
)

func main() {
    label := string([]byte{97, 98, 99, 0, 0, 0, 0})
    fmt.Println(strings.TrimSpace(label))
}

您可以使用sys package:

package main
import "golang.org/x/sys/windows"

func main() {
   b := []byte{97, 98, 99, 0, 0, 0, 0}
   s := windows.ByteSliceToString(b)
   println(s == "abc")
}

或者你可以自己實現它:

package main
import "bytes"

func byteSliceToString(s []byte) string {
   n := bytes.IndexByte(s, 0)
   if n >= 0 {
      s = s[:n]
   }
   return string(s)
}

func main() {
   b := []byte{97, 98, 99, 0, 0, 0, 0}
   s := byteSliceToString(b)
   println(s == "abc")
}

在 go 1.18+ 中,您可以使用bytes.Cut

import (
    "bytes"
)

func bytesToStr(in []byte) string {
    str, _, _ := bytes.Cut(in, []byte{0})
    return string(str)
}

一. 字符串 .TrimSpace .TrimRight

//修剪尾部'\0',但不能處理像“abc\x00def\x00”這樣的字節。

無法編輯@orelli 答案,所以在這里寫道:

package main

import (
    "fmt"
    "strings"
)

func main() {
    label := string([]byte{97, 98, 99, 0, 0, 0, 0})

    s1 := strings.TrimSpace(label)
    fmt.Println(len(s1), s1)

    s2 := strings.TrimRight(label, "\x00")
    fmt.Println(len(s2), s2)
  }

output:

7 abc????
3 abc

//? 是 '\0' ,此處無法顯示。


所以
.TrimSpace不能修剪 '\0',但是
.TrimRight加上 "\x00" 即可。



二. bytes.IndexByte

搜索第一個 '\0',可能不支持 utf-8

package main

import (
    "bytes"
    "fmt"
    "strings"
)

func main() {
    b_arr := []byte{97, 98, 99, 0, 100, 0, 0}
    label := string(b_arr)

    s1 := strings.TrimSpace(label)
    fmt.Println(len(s1), s1)   //7 abc?d??

    s2 := strings.TrimRight(label, "\x00")
    fmt.Println(len(s2), s2)   //5 abc?d

    n := bytes.IndexByte([]byte(label), 0)
    fmt.Println(n, label[:n])  //3 abc

    s_arr := b_arr[:bytes.IndexByte(b_arr, 0)]
    fmt.Println(len(s_arr), string(s_arr)) //3 abc
}

相等的

n1 := bytes.IndexByte(b_arr, 0)
n2 := bytes.Index(b_arr, []byte{0})

n3, c := 0, byte(0)
for n3, c = range b_arr {
    if c == 0 {
        break
    }
}

第一個答案是行不通的!!

func TrimSpace(s []byte) []byte {
    return TrimFunc(s, unicode.IsSpace)
}

func IsSpace(r rune) bool {
    // This property isn't the same as Z; special-case it.
    if uint32(r) <= MaxLatin1 {
        switch r {
        case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
            return true
        }
        return false
    }
    return isExcludingLatin(White_Space, r)
}

func IsSpace中根本沒有“\\ x00”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM