1 回答

TA貢獻2011條經驗 獲得超2個贊
靜態方法返回從指定的UTF-16
String.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
[]rune
rune
int32
換句話說,區別在于:
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.Println
和console.log
做。
首先讓我聲明,您的 Go 代碼恰好在沒有使用我建議的正確解碼的情況下正常工作——因為切片中的所有整數都是“基本”范圍內的 UTF-16 代碼單元,所以“啞”轉換有效,并且生成與 JS 代碼相同的字符串。
要“按原樣”查看這兩個字符串,您可以這樣做:
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(記錄分隔符)。
…等等。
對于 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
不會那樣做:它只是將這些字節“按原樣”發送到輸出。
希望這可以解釋觀察到的差異。
- 1 回答
- 0 關注
- 238 瀏覽
添加回答
舉報