Golang字符串操作:UTF-8编码与字节切片详解
Golang字符串操作:UTF-8编码与字节切片详解 大家好,我正在阅读这篇关于Go语言字符串的博客:https://go.dev/blog/strings
我尝试进行了一些实验,发现 sample 和 sample[0] 的输出结果不同,如下所示。我知道UTF-8编码的Unicode字符“½”(二分之一)应该是 "\xc2\xbd",所以 sample 的输出对我来说更合理。有人能帮我理解为什么打印单个字节却能产生正确的UTF-8编码字符吗?
package main
import "fmt"
func main() {
var sample = "\xbd"
fmt.Println("Println:")
fmt.Println(sample)
fmt.Printf("%q, %q\n", sample, sample[0])
}
更多关于Golang字符串操作:UTF-8编码与字节切片详解的实战教程也可以访问 https://www.itying.com/category-94-b0.html
打印/转换不同的数据类型。
package main
import "fmt"
func main() {
var sample = "\xbd"
banana := sample[0]
// DB hex = 189 decimal
fmt.Printf("banana: %d \n", banana)
// 189 decimal in string (ASCII table) = ½ https://www.ascii-code.com/CP1252/189
fmt.Printf("%[1]s, %[1]q, %[2]q, %[2]U, %[1]T, %[2]T", sample, banana)
}
输出: banana: 189 �, “\xbd”, ‘½’, U+00BD, string, uint8
更多关于Golang字符串操作:UTF-8编码与字节切片详解的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
等等,我不太明白你的问题是什么?你是想知道为什么用 %q 吗? %q 是一个用 Go 语法安全转义的双引号字符串。
参见:fmt/format.go
// fmtQ formats a string as a double-quoted, escaped Go string constant.
// If f.sharp is set a raw (backquoted) string may be returned instead
// if the string does not contain any control characters other than tab.
func (f *fmt) fmtQ(s string) {
s = f.truncateString(s)
if f.sharp && strconv.CanBackquote(s) {
f.padString("`" + s + "`")
return
}
buf := f.intbuf[:0]
if f.plus {
f.pad(strconv.AppendQuoteToASCII(buf, s))
} else {
f.pad(strconv.AppendQuote(buf, s))
}
}
在Go语言中,字符串本质上是只读的字节切片([]byte),每个字节对应的是UTF-8编码的单个字节。当你使用 sample = "\xbd" 时,字符串包含的是单个字节 0xbd,而不是完整的UTF-8编码序列。
关键点解释:
- UTF-8编码规则:Unicode字符“½”(U+00BD)的完整UTF-8编码是
"\xc2\xbd"(两个字节)。但你的代码中"\xbd"只是一个字节,它本身是无效的UTF-8编码(因为UTF-8中,以0xbd开头的字节不是合法的起始字节)。 - 输出差异:
fmt.Println(sample):直接打印字符串时,Go会尝试将字节解释为UTF-8字符。由于0xbd是无效编码,Go会使用Unicode替换字符(�,U+FFFD)来替代,因此输出可能显示为乱码或占位符。sample[0]:访问sample[0]会返回字节值0xbd(类型为byte),而fmt.Printf("%q", sample[0])会将该字节转换为ASCII/UTF-8可打印形式。由于0xbd不是可打印ASCII字符,%q会将其转义为十六进制形式"\xbd"。
示例代码验证:
package main
import "fmt"
func main() {
// 正确编码的Unicode字符 "½"
correct := "\xc2\xbd"
fmt.Printf("完整UTF-8编码: %q\n", correct) // 输出: "½"
// 单个字节(无效UTF-8)
singleByte := "\xbd"
fmt.Printf("单个字节字符串: %q\n", singleByte) // 输出: "\xbd"(转义形式)
fmt.Printf("字节值: 0x%x\n", singleByte[0]) // 输出: 0xbd
// 遍历字节切片展示编码差异
fmt.Println("\n字节切片对比:")
fmt.Printf("correct (UTF-8): % x\n", []byte(correct)) // 输出: c2 bd
fmt.Printf("singleByte: % x\n", []byte(singleByte)) // 输出: bd
}
输出说明:
- 当字符串包含无效UTF-8字节时,直接打印可能显示乱码,但通过
%q或字节切片可以查看原始字节值。 - 你的代码中
sample[0]返回的是字节0xbd,%q将其格式化为转义字符串"\xbd",这不是正确的UTF-8字符“½”,而只是字节的字面量表示。
总结: 要正确表示Unicode字符“½”,必须使用完整的UTF-8编码 "\xc2\xbd"。单个字节 "\xbd" 是无效编码,其输出结果取决于上下文(打印方式)。

