亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

無效字符的字節到字符串轉換

無效字符的字節到字符串轉換

Go
元芳怎么了 2022-10-24 15:52:41
我需要解析可能無效或包含一些錯誤的 UDP 數據包。我想用.字節到字符串轉換后替換無效字符,以顯示數據包的內容。我該怎么做?這是我的代碼:func main() {   a := []byte{'a', 0xff, 0xaf, 'b', 0xbf}   s := string(a)   s = strings.Replace(s, string(0xFFFD), ".", 0)   fmt.Println("s: ", s) // I would like to display "a..b."   for _, r := range s {      fmt.Println("r: ", r)   }   rs := []rune(s)   fmt.Println("rs: ", rs)}
查看完整描述

3 回答

?
交互式愛情

TA貢獻1712條經驗 獲得超3個贊

您的方法的根本問題是類型轉換[]byte為的結果中string沒有任何U+FFFDs :此類型轉換僅將字節從源逐字復制到目標。
就像字節切片一樣,Go 中的字符串沒有義務包含 UTF-8 編碼的文本;它們可以包含任何數據,包括與文本無關的不透明二進制數據。

但是對字符串的一些操作——即將它們類型轉換為[]rune使用它們迭代range——確實將字符串解釋為 UTF-8 編碼的文本。這正是你被絆倒的地方:你的range調試循環試圖解釋字符串,每次解碼正確編碼的代碼點的嘗試失敗時,都會range產生一個替換字符,U+FFFD.
重申一下,通過類型轉換獲得的字符串不包含您希望被正則表達式替換的字符。

至于如何從您的數據中實際生成有效的 UTF-8 編碼字符串,您可以采用兩步過程:

  1. 將你的字節切片類型轉換為字符串——就像你已經做的那樣。

  2. 使用任何將字符串解釋為 UTF-8 的方法——替換將在此過程中動態出現的 U+FFFD——在您進行迭代時。

像這樣的東西:

var sb strings.Builder

for _, c := range string(b) {

  if c == '\uFFFD' {

    sb.WriteByte('.')

  } else {

    sb.WriteRune(c)

  }

}

return sb.String()

關于性能的說明:由于將 a 類型轉換[]byte為string復制內存——因為字符串是不可變的,而切片不是——類型轉換的第一步可能會浪費處理大量數據和/或緊密工作的代碼的資源處理循環。

在這種情況下,可能值得使用適用于字節片的包的DecodeRune功能。encoding/utf8它的文檔中的一個例子可以很容易地適應上面的循環。



查看完整回答
反對 回復 2022-10-24
?
湖上湖

TA貢獻2003條經驗 獲得超2個贊

您可能希望strings.ToValidUTF8()用于此:


ToValidUTF8 返回字符串 s 的副本,其中每次運行無效的 UTF-8 字節序列都被替換字符串替換,該替換字符串可能為空。


它“似乎”完全符合您的需要。測試它:


a := []byte{'a', 0xff, 0xaf, 'b', 0xbf}

s := strings.ToValidUTF8(string(a), ".")

fmt.Println(s)

輸出(在Go Playground上試試):


a.b.

我寫“貌似”是因為如您所見,a和b: 之間只有一個點,因為可能有 2 個字節,但有一個無效序列。


請注意,您可以避免[]byte=>string轉換,因為有一個bytes.ToValidUTF8()等價的操作并返回 a []byte:


a := []byte{'a', 0xff, 0xaf, 'b', 0xbf}

a = bytes.ToValidUTF8(a, []byte{'.'})

fmt.Println(string(a))

輸出將是相同的。在Go Playground上試試這個。


如果您對多個(無效序列)字節可能會縮小為一個點感到困擾,請繼續閱讀。


另請注意,要檢查可能包含或不包含文本的任意字節切片,您可以簡單地使用hex.Dump()which 生成如下輸出:


a := []byte{'a', 0xff, 0xaf, 'b', 0xbf}

fmt.Println(hex.Dump(a))

輸出:


00000000  61 ff af 62 bf                                    |a..b.|

您的預期輸出a..b.包含其他(有用的)數據,例如十六進制偏移量和字節的十六進制表示。


要獲得“更好”的輸出圖片,請嘗試使用更長的輸入:


a = []byte{'a', 0xff, 0xaf, 'b', 0xbf, 50: 0xff}

fmt.Println(hex.Dump(a))


00000000  61 ff af 62 bf 00 00 00  00 00 00 00 00 00 00 00  |a..b............|

00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

00000030  00 00 ff                                          |...|


查看完整回答
反對 回復 2022-10-24
?
慕桂英4014372

TA貢獻1871條經驗 獲得超13個贊

并且非常清楚地解釋了從字符串中掃描 unicode 符文的問題。


只需添加以下注釋:如果您的意圖是僅查看 ASCII 范圍內的字符(可打印字符 < 127)并且您并不真正關心其他 unicode 代碼點,您可以更直率:


// create a byte slice with the same byte length as s

var bs = make([]byte, len(s))


// scan s byte by byte :

for i := 0; i < len(s); i++ {

    switch {

    case 32 <= s[i] && s[i] <= 126:

        bs[i] = s[i]


    // depending on your needs, you may also keep characters in the 0..31 range,

    // like 'tab' (9), 'linefeed' (10) or 'carriage return' (13) :

    // case s[i] == 9, s[i] == 10, s[i] == 13:

    //   bs[i] = s[i]


    default:

        bs[i] = '.'

    }

}



fmt.Printf("rs: %s\n", bs)



這個功能會給你一些接近“文本”部分的東西hexdump -C。


查看完整回答
反對 回復 2022-10-24
  • 3 回答
  • 0 關注
  • 161 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號