Go 语言字符串简述

147 阅读4分钟

Go 语言字符类型本质

在 Go 语言中没有字符类型, 用byte 和 rune 类型表示字符。而在 Go 中, byte 和 rune 类型都是整型的别名,所以字符只是整数的特殊用例。

  • Go 语言的字符有以下两种:
  1. byte 型,其实质是uint8类型,代表一个ASCII码字符。
  2. rune类型,其实质是int32类型,代表一个 UTF-8字符。因此Go 使用 rune 类型来处理 Unicode。

为什么需要两种类型?

byte 占用一个字节,因此它可以用于表示 ASCII 字符;而 UTF-8 是一种变长的编码方法,字符长度从 1 个字节到 4 个字节不等。byte 显然不擅长这样的表示,就算你想要使用多个 byte 进行表示,你也无从知晓你要处理的 UTF-8 字符究竟占了几个字节。

字符串组成

组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(’)包裹起来,如:

var a ='s'
var b ='学'

也可利用反引号字符实现多行字符串定义

str := `first line
second line
third line`
fmt.Println(str)

输出:

first line 
second line
third line 

字面量,操作符和转义

在Go语言中,字符串字面量使用双引号 "" 或者反引号 ' 来创建。双引号用来创建可解析的字符串,支持转义,但不能用来引用多行;反引号用来创建原生的字符串字面量,可能由多行组成,但不支持转义,并且可以包含除了反引号外其他所有字符。双引号创建可解析的字符串应用最广泛,反引号用来创建原生的字符串则多用于书写多行消息,HTML以及正则表达式。

比如下面的这些例子,输出结果完全一致:

text1 := "\"Hello GoLang\",I said"
text2 :=`"Hello GoLang",I said`

常用字符串转义符如下表所示:

转义符含义
\r回车符(返回行首)
\n换行符(直接跳到下一行的同列位置)
\t制表符
\'单引号
\"双引号
\\反斜杠

有关字符串的一些基础操作

text1 := "abcdefg"	
text1[n]	   获取字符串索引位置为n的原始字节,比如a为97
text1[n:m])	   截取得字符串索引位置为 n 到 m-1 的字符串
text1[n:]	   截取得字符串索引位置为 n 到 len(s)-1 的字符串
text1[:m]	   截取得字符串索引位置为 0 到 m-1 的字符串
utf8.RuneCountInString(text1) 	获取字符串字符的个数
[]rune(text1)	   将字符串的每一个字符转换为码点值,比如这里会输出[97 98 99 100 101 102 103]
[]byte(text1)	   功能同上,但是只适用于ASCII码字符
string(text1[n]	   获取字符串索引位置为n的字符值

字符串遍历

方法一:通过每个字符串的下标进行遍历

由于在 Go 语言中,字符串以 UTF-8 编码方式存储,通过下标索引字符串,每次只产生一个字节。因此,如果是ASCII码字符,则每个字符刚好对应一个字节,利用下标可以正常索引;如果字符串中含有 UTF-8 编码字符,例如中文时就会出现乱码,因为在UTF-8一个汉字占3个字节,所以一个汉字将产生三个下标。

s := "hello生活"
for i := 0; i < len(s); i++ {
	fmt.Printf("%v(%c) ", s[i], s[i])
}
-----------------------------------------------------------------------
输出:
104(h) 101(e) 108(l) 108(l) 111(o) 231(ç) 148(²) 159(²) 230(æ) 180(´) 187(») 

以上述代码为例,从输出结果可以看出,前面英文部分,一个字母对应一个字节,通过%c也可以获得该值对应的Unicode码值;而后面的汉字,可以看出,两个汉字产生了6个字节,从而在转义的时候出现错误。

方法二:通过for range 进行遍历

range 遍历则会得到 rune 类型的字符,其实质是int32类型,代表一个 UTF-8字符。因此Go 使用 rune 类型来处理 Unicode。

s := "hello生活"
for _, r := range s { 
	fmt.Printf("%v(%c) ", r, r)
}
-----------------------------------------------------------------------
输出:
104(h) 101(e) 108(l) 108(l) 111(o) 29983(生) 27963(活)

从结果可知,r每次得到一个int32类型( rune 类型)的值,通过%c可以获得该值对应的Unicode码值。

总结:对于ASCII 字符串遍历可以直接使用下标,而对于包含Unicode 字符串遍历用 for range。