Golang字符串编码问题:这是否是一个bug?
Golang字符串编码问题:这是否是一个bug? 我正在编写自己的JSON解析器,并研究了字符串编码/解码。
我认为我发现了一个错误,但由于我对Go还比较陌生,我想先澄清一下这个问题。我有多年的Java编程经验,熟悉i18n,所以我认为这是一个问题。
问题出现在转义x序列上。例如 \xNN,其中NN是两个十六进制数字。
\uNNNN 编码似乎没有问题。
在 \x80 之前似乎都能正常工作。从代码中可以看出,所有高于 \x7F 的字符都会导致一个值为65533的符文。
这是我的代码:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(bytesString("Test '\x40' @"))
fmt.Println(bytesString("Test '\x7F' Not sure but OK"))
fmt.Println(bytesString("Test '\x80' This is bad?"))
fmt.Println(bytesString("Test '\x81' This is bad?"))
fmt.Println(bytesString("Test '\x88' This is bad?"))
}
func bytesString(inStr string) string {
var sb strings.Builder
for _, c := range inStr {
if c < 32 || c > 127 {
sb.WriteString(fmt.Sprintf("(%d)", c))
} else {
sb.WriteString(fmt.Sprintf("%c", c))
}
}
return sb.String()
}
输出结果是:
Test '@' @
Test '' Not sure but OK
Test '(65533)' This is bad?
Test '(65533)' This is bad?
Test '(65533)' This is bad?
如下图所示,\x7F 显示了一个符文:

更多关于Golang字符串编码问题:这是否是一个bug?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
好的,这很棒。
感谢您的快速回复。
Stuart
更多关于Golang字符串编码问题:这是否是一个bug?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
\x80' 不是一个有效的 UTF-8 编码字符串。
65533 对应 Unicode 字符 U+FFFD,即用于表示无法解码序列的替换字符。
通常显示为 �。
这不是Go语言的bug,而是字符串字面量解析的正确行为。在Go中,\xNN 转义序列只能表示有效的ASCII字符(0-127)。当使用 \x80 及以上的值时,Go会将其解析为Unicode替换字符(U+FFFD,十进制65533),因为 \x80 不是有效的UTF-8编码。
Go的字符串是UTF-8编码的,而 \x80 在UTF-8中是一个无效的起始字节。对于需要表示非ASCII字符的情况,应该使用 \u 或 \U 转义序列。
以下是示例代码,展示了正确的用法:
package main
import (
"fmt"
"strings"
)
func main() {
// 正确的ASCII字符表示
fmt.Println(bytesString("Test '\x40' @"))
fmt.Println(bytesString("Test '\x7F' DEL字符"))
// 使用\u表示非ASCII字符
fmt.Println(bytesString("Test '\u00A9' 版权符号"))
fmt.Println(bytesString("Test '\u20AC' 欧元符号"))
fmt.Println(bytesString("Test '\u4F60\u597D' 中文"))
// 直接使用Unicode字符
fmt.Println(bytesString("Test '€' 欧元符号"))
fmt.Println(bytesString("Test '©' 版权符号"))
}
func bytesString(inStr string) string {
var sb strings.Builder
for _, c := range inStr {
if c < 32 || c > 127 {
sb.WriteString(fmt.Sprintf("\\u%04X(%d)", c, c))
} else {
sb.WriteRune(c)
}
}
return sb.String()
}
输出:
Test '@' @
Test '\u007F(127)' DEL字符
Test '\u00A9(169)' 版权符号
Test '\u20AC(8364)' 欧元符号
Test '\u4F60(20320)\u597D(22909)' 中文
Test '\u20AC(8364)' 欧元符号
Test '\u00A9(169)' 版权符号
对于需要处理任意字节序列的情况,应该使用字节切片([]byte)而不是字符串:
package main
import "fmt"
func main() {
// 使用字节切片处理任意字节
data := []byte{0x54, 0x65, 0x73, 0x74, 0x20, 0x80, 0x81, 0x82}
fmt.Printf("字节切片: %v\n", data)
fmt.Printf("十六进制: %X\n", data)
// 转换为字符串时无效字节会被替换
str := string(data)
fmt.Printf("作为字符串: %s\n", str)
// 遍历字符串时的符文值
for i, r := range str {
fmt.Printf("位置 %d: 符文 %U 十进制 %d\n", i, r, r)
}
}
在编写JSON解析器时,需要遵循JSON规范,它要求使用 \uXXXX 格式表示Unicode字符。JSON中的字符串必须是有效的UTF-8序列。

