Tags: Golang
Published: 2024年6月19日
概要: This blog reflects on the different ways of iterating over strings in Golang, highlighting common mistakes and explaining the differences between Unicode and UTF-8 encoding.
起初学习时,并没有关注string的存储方式以及unicode和utf-8编码的区别,故出现了很滑稽的问题,在处理字符串时,使用错误的方法,导致得到的类型不正确,在继续追究错误原因时,发现一些帖子写的并不是很清晰。
首先介绍一个最低级的错误:
gos := "abc你好"
for v := range s{
fmt.Println(v)
}
起初我以为这样遍历得到的v会是每个字符(新手狠狠拍脑子!),然而这样得到的v是每个字符位置的下标:0、1、2、3、6。
接下来应该主要讨论另外两种方式,但是在此之前先介绍一下unicode
和utf-8
的区别。此处引用(Unicode和UTF-8有什么区别 • Worktile社区)的内容。
在了解上面内容之后,还需要知道Go语言的默认编码是UTF-8。 在Go语言中,字符串的默认编码就是UTF-8,这也是Go语言内部使用的字符编码格式。 Go语言的源代码也默认使用UTF-8编码格式。这也是后面出现问题的原因所在。
先看for range的这个方法。i
与v
分别是s的每个字符的下标和他的unicode
码点(后面解释)。
gos := "abc你好"
for i,v := range s{
fmt.Printf("index:%d, value: %d\n", i, v)
}
/*
index:0, value: 97
index:1, value: 98
index:2, value: 99
index:3, value: 20320
index:6, value: 22909
*/
观察以上输出,我们会发现对于前三个字符,即英文字符,index分别为0、1、2,但是到了后面中文部分出现了变化,index变为了3、6。上面介绍了UTF-8编码是不定长的,即一个字符可能需要不同字节的空间存储。结合index的值,可以猜测,此处index的值为字符串的每个字符的第一个字节相对于字符串首地址的索引。出现上面这样的结果说明对于abc
字符各只占用一个字节,而后面的中文占用了3个字节。
换一种方式打印:
gos := "abc你好"
for i, v := range s {
fmt.Printf("index:%d, value: %c\n", i, v)
}
/*
index:0, value: a
index:1, value: b
index:2, value: c
index:3, value: 你
index:6, value: 好
*/
使用%c
打印的是对应的 Unicode 码点表示的字符。因此可以得到结论,上面的value值为字符所对应的unicode码点的值。
那么在讨论清楚上面的内容之后,我们再看另外一个方式。
gos := "abc你好"
for i := 0; i < len(s); i++ {
fmt.Printf("index:%d, value: %d\n", i, s[i])
}
/*
index:0, value: 97
index:1, value: 98
index:2, value: 99
index:3, value: 228
index:4, value: 189
index:5, value: 160
index:6, value: 229
index:7, value: 165
index:8, value: 189
*/
我们发现index一直从0打印到8,很奇怪的现象,但是结合for range打印的结果分析来看,恰好字符串s的字节数为9,abc
各占一个字节,而你好
各占用三个字节。因此,很容易想到此处value的值为UTF-8编码中,每个字节的值。
换用%c
打印:
gos := "abc你好"
for i := 0; i < len(s); i++ {
fmt.Printf("index:%d, value: %c\n", i, s[i])
}
/*
index:0, value: a
index:1, value: b
index:2, value: c
index:3, value: ä
index:4, value: ½
index:5, value:
index:6, value: å
index:7, value: ¥
index:8, value: ½
*/
果然从c之后,出现了6个奇怪的结果,因为将你好
的UTF-8编码转化为了6个编码,再分别将他们在unicode字符集中代表的字符打印出来,出现这些结果。
简单总结一下:
rune
(是可以认为,起码这样比较类型是正确的,处理中文字符串时这样使用)。byte
。至此,遇到的问题解释清楚。写的很啰嗦,因为自己之前基础很差,很少深究过代码出现错误的底层原因,所以借此次机会写的详细一些,希望能够对看到此文的人有所帮助。
本文作者:AstralDex
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!