开门见山,抛出结论:"Go语言中字符串第i项并不一定是第i个字符"。
初看这句话可能不太理解,下面我举例说明:
func main() {
var name string = "zhang"
fmt.Println(name[1]) //print 104
}
name[1]对应的值是h ,h对应的值是104,有同学要说了,这不就证明"Go语言中字符串第i项是第i个字符"吗? 莫着急,我们接着看下面的一个案例:
func main() {
var name string = "哈hang"
fmt.Println(name[1]) //print 147
}
把字符'z'改成了字符'哈',name[1]结果就发生了变化。
通过上面的两个案例,我们已经证明了:"Go语言中字符串第i项并不一定是第i个字符"。那么怎么才能使得案例2和案例1的结果一致呢?如下处理案例3:
func main() {
var name string = "哈hang"
fmt.Println([]rune(name)[1]) //print 104
}
出现案例1和案例2结果差异的原因:Go语言中基础数据类型:string字符串类型底层数据结构是数组,它是byte类型,在JAVA语言中引用数据类型:String字符串类型底层数据结构也是数组,它是char类型。而Go语言中默认字符是通过UTF-8
进行编码,我们知道在UTF-8
编码中:"一个中文等于三个字节,中文标点占三个字节,一个英文字符等于一个字节,英文标点占一个字节。"
func main() {
var name string = "哈hang"
fmt.Println([]rune(name), fmt.Sprintf("%d", len([]rune(name)))) //[21704 104 97 110 103] 5
fmt.Println([]byte(name), fmt.Sprintf("%d", len([]byte(name)))) //[229 147 136 104 97 110 103] 7
}
所以,Go中才出现了案例1和案例2的差异,但JAVA语言中并不会出现上述的现象。
接下来,解释下案例3中rune
的用法,引用官方的原话:
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
//int32的别名,几乎在所有方面等同于int32
//它用来区分字符值和整数值
type rune = int32
在Go语言中定义字符有两种方式:
unit8
类型( byte
<==> unit8
,两者同意不同名),表示 ASCII 码的一个字符,占用 1 个字节。rune
类型,代表一个 UTF-8
字符,当需要处理中文、日文或者其他复合字符时,则需要用到 rune
类型。 rune
类型等价于 int32
类型,占用 4 个字节。综上,案例3也可以写成:
func main() {
var name string = "哈hang"
fmt.Println([]int32(name)[1]) //print 104
}
由于Go语言字符串底层是byte
类型,可以预想,通过内置函数len()
获取字符串的长度实际值与我们预想值会不一样。如下案例4:
func main() {
var name string = "哈hang"
fmt.Println(len(name)) //预想值是5,实际值是7
}
如果我们需要预期值5,应该如何实现呢?如下案例5:
import (
"fmt"
"unicode/utf8"
)
func main() {
var name string = "哈hang"
//以下两种都可以得到str的字符串长度
//golang中的unicode/utf8包提供了用utf-8获取长度的方法
fmt.Println("RuneCountInString:", utf8.RuneCountInString(name)) //5
//通过rune类型处理unicode字符
fmt.Println("rune:", len([]rune(name))) //5
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。