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

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

將 Golang rune 轉換為 utf-8 結果與 js string.fromCharCode

將 Golang rune 轉換為 utf-8 結果與 js string.fromCharCode

Go
慕后森 2023-02-21 16:42:59
去var int32s = []int32{  8, 253, 80, 56, 30, 220, 217, 42, 235, 33, 211, 23, 231, 216, 234, 26,}fmt.Println("word: ", string(int32s))jslet int32s = [8, 253, 80, 56, 30, 220, 217, 42, 235, 33, 211, 23, 231, 216, 234, 26]str = String.fromCharCode.apply(null, int32s);console.log("word: " + String.fromCharCode.apply(null, int32s))對于一些空字符,上面的 2 個結果是不一樣的。是否有任何解決方案可以修改 go 代碼以生成與 js 相同的結果?
查看完整描述

1 回答

?
森林海

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

引用文檔String.fromCharCode

靜態方法返回從指定的UTF-16String.fromCharCode()代碼單元序列創建的字符串。

因此,數組中的每個數字int32s都被解釋為提供 Unicode 代碼單元的 16 位整數,因此整個序列被解釋為形成 UTF-16 編碼字符串的一系列代碼單元
我要強調最后一點,因為從變量的命名來看—— int32s,——無論 JS 代碼的作者是誰,他們似乎對那里發生的事情有錯誤的想法。

現在回到 Go 的對應部分。Go 沒有內置對 UTF-16 編碼的支持;它的字符串通常使用UTF-8編碼(雖然它們不是必需的,但我們不要離題),并且 Go 還提供數據rune類型,它是int32. 符文是一個 Unicode 代碼點,即一個能夠包含完整 Unicode 字符的數字。(稍后我會回到這個事實及其與 JS 代碼的關系。)

現在,你的問題在于它以與(記住 a是 的別名)相同的方式string(int32s)插入你的 s 切片,因此它采用切片中的每個數字來表示單個 Unicode 字符并生成它們的字符串。(這個字符串在內部編碼為 UTF-8,但這個事實與問題無關。)int32[]runeruneint32

換句話說,區別在于:

  • JS 代碼將數組解釋為表示 UTF-16 編碼字符串的 16 位值序列,并將其轉換為某種內部字符串表示形式。

  • Go 代碼將切片解釋為 32 位 Unicode 代碼點序列,并生成包含這些代碼點的字符串。

Go 標準庫生成了一個處理 UTF-16 編碼的包:encoding/utf16,我們可以使用它來執行 JS 代碼編碼的操作——將 UTF-16 編碼的字符串解碼為一系列 Unicode 代碼點,然后我們可以轉換為 Go 字符串:

package main


import (

    "fmt"

    "unicode/utf16"

)


func main() {

    var uint16s = []uint16{

        8, 253, 80, 56, 30, 220, 217, 42, 235, 33, 211, 23, 231, 216, 234, 26,

    }


    runes := utf16.Decode(uint16s)


    fmt.Println("word: ", string(runes))

}

游樂場。


(請注意,我已將切片的類型更改為[]unit16并相應地重命名。此外,我已將源切片解碼為明確命名的變量;這樣做是為了清楚起見——突出顯示正在發生的事情。)

此代碼會產生與 Firefox 控制臺中的 JS 代碼相同的亂碼。

更新

對于一些空字符,上面的 2 個結果是不一樣的。

我沒有碰過的一點。

據我了解,問題是您的 Go 代碼打印出類似的東西,
yP8üù*?!ó??ê
而 JS 代碼打印
?yP8?üù*?!ó???ê?
正確嗎?

這里的問題在于對結果字符串的不同解釋fmt.Printlnconsole.log做。

首先讓我聲明,您的 Go 代碼恰好在沒有使用我建議的正確解碼的情況下正常工作——因為切片中的所有整數都是“基本”范圍內的 UTF-16 代碼單元,所以“啞”轉換有效,并且生成與 JS 代碼相同的字符串。
要“按原樣”查看這兩個字符串,您可以這樣做:

  1. fmt.Printf對于 Go,與動詞一起使用%q以在打印輸出中使用 Go 規則查看“轉義”的“特殊”Unicode(和 ASCII)字符:

    fmt.Println("%q\n", string(int32s))
    產生
    "\byP8\x1eüù*?!ó\x17??ê\x1a"

    注意這些 '\b'、'\x1e' 和其他轉義符:

    如您所見,這些是不可打印的控制字符。

    • '\b' 是 ASCII BS(退格)控制字符,代碼 0x08 — 請參閱http://man-ascii.com/。

    • '\x1e'是一個字節,代碼為0x1E,是ASCII RS(記錄分隔符)。

    • …等等。

  2. 對于 JS,無需使用即可打印結果字符串的值console.log——只需將其值保存在變量中,然后在控制臺輸入其名稱并按 Enter——“按原樣”打印其值:

    > let int32s = [8, 253, 80, 56, 30, 220, 217, 42, 235, 33, 211, 23, 231, 216, 234, 26]
    > str = String.fromCharCode.apply(null, int32s);
    > str"\u0008yP8\u001eüù*?!ó\u0017??ê\u001a"

    請注意,該字符串包含“\uXXXX”轉義符。它們定義了 Unicode 代碼點(BTW Go 支持相同的語法),并且這些轉義定義了與 Go 示例中相同的代碼點:

    • “\u0008”是一個代碼為 8 或 0x08 的字符。

    • "\u001e" 是一個代碼為 0x1E 的字符。

    • …等等。

如您所見,生成的字符串是相同的,唯一的區別是 Go 的字符串是用 UTF-8 編碼的,因此,使用并查看編碼字節來查看其內容,這就是 Gofmt.Printf打印它們%q的原因“轉義”使用“最小”編碼,但我們也可以使用 JS 示例中的轉義:您可以檢查而不是運行 prints 。
fmt.Println("\byP8\x1eüù*?!ó\x17??ê\x1a" == "\u0008yP8\u001eüù*?!ó\u0017??ê\u001a")
true

因此,正如您現在看到的,console.log用特殊的 Unicode 代碼點 U+FFFD 替換每個不可打印的字符,這稱為 Unicode 替換字符,通常呈現為帶有白色問號的黑色菱形。
Gofmt.Println不會那樣做:它只是將這些字節“按原樣”發送到輸出。

希望這可以解釋觀察到的差異。


查看完整回答
反對 回復 2023-02-21
  • 1 回答
  • 0 關注
  • 238 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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