计算机是二进制的,字符最终也是转换成二进制保存起来的。字符集就是定义字符对应的数值。 Unicode是一个字符集,为每个字符规定一个用来表示该字符的数字,但是并没有规定该数字的二进制保存方式,utf8规定了对于unicode值的二进制保存方式。
utf8是可变长度字符编码,不同的字符会对应不同大小的存储方式,比如"a"字符(unicode值97)用1个字节,而"中"字符(unicode值20013)则用3个字节。字符的unicode值决定了字符需要用多少字节表示
Go语言中,string就是只读的采用utf8编码的字节切片(slice) 因此用len函数获取到的长度并不是字符个数,而是字节个数。 for循环遍历输出的也是各个字节。
a := "Randal";
for i := 0; i < len(a); i++ {
fmt.Printf("%x ", a[i])
fmt.Printf("%c ", a[i])
}
// 输出结果
52 61 6e 64 61 6c
Randal
复制代码
a := "中国";
fmt.Println(len(a))
for i := 0; i < len(a); i++ {
fmt.Printf("%x ", a[i])
}
for i := 0; i < len(a); i++ {
fmt.Printf("%c ", a[i])
}
// 输出结果
6
E4 B8 AD E5 9B BD
ä¸å½
复制代码
fmt.Printf函数支持从一个表达式列表生成格式化的输出,它的第一个参数是格式化指示字符串,由它指定其他参数如何格式化。其中%c,用于输出字符(Unicode码点),码点是字符的unicode值。 由于go采用的是utf8编码,而“中”的utf8编码是E4 B8 AD(所表示的unicode值是U+4E2D), https://unicode-table.com/en/00E4/ 通过这个链接可以看到ä的unicode编码就是U+00E4。
从上面的例子中可以看出当字符的utf8编码超过1个字节的时候格式化输出单个字符就会出现乱码的情况,如果希望解决乱码问题就要用到rune了
rune是int32的别名,代表字符的Unicode编码,采用4个字节存储,将string转成rune就意味着任何一个字符都用4个字节来存储其unicode值,这样每次遍历的时候返回的就是unicode值,而不再是字节了,这样就可以解决乱码问题了
var s string
s = "中国"
r := []rune(s)
for i := 0; i < len(r); i++ {
fmt.Printf("%x", r[i])
}
for i := 0; i < len(r); i++ {
fmt.Printf("%c", r[i])
}
// 输出结果
4e2d 56fd
中国
复制代码
通过for range对字符串进行遍历时,每次获取到的对象都是rune类型的,因此下面的方式也可以解决乱码问题
var s string
s = "中国"
for _, item := range s {
fmt.Printf("%c", item)
}
// 输出结果
中国
复制代码
bytes操作的对象也是字节切片,与string的不可变不同,byte是可变的,因此string按增量方式构建字符串会导致多次内存分配和复制,使用bytes就不会因而更高效一点
package main
import (
"fmt"
"bytes"
)
func main() {
var s string
s = "中国"
var b bytes.Buffer
b.WriteString("中国")
for i := 0; i < 10; i++ {
s += "a"
b.WriteString("a")
}
fmt.Println(s)
fmt.Println(b.String())
}
原文:https://www.cnblogs.com/lovezbs/p/12879168.html