golang中 String bytes rune 和 字符概念与应用

发布时间 2023-11-07 19:29:06作者: 橙皮^-^

一、引入问题-为何打印s[0] 没有打印‘你’字符

package main

import "fmt"

func main() {
	s := "你"
	fmt.Println(s[0])
	fmt.Printf("%s\n", s[0])
}
  • output
%!s(uint8=228)

首先需要知道go中编码格式和String 类型, Go内置的utf-8编码格式。

二、utf-8编码 与 Unicode

  • Unicode,全称为Unicode标准(The Unicode Standard),其官方机构Unicode联盟所用的中文名称为统一码,为各种语言中的每个字符定义一个唯一的编码,也描述为码点。
  • utf-8编码 是一种可变长编码方式,可以用一至四个字节对有效码点进行编码。

‘a' 对应的Unicode值为U+0061 -- utf-8编码后自己 “\x61”(前128个字符与ASCII编码兼容)
‘你’ 对应的Unicode值为U+4F60 -- utf-8编码后字节 “\xe4\xbd\xa0”

三、String类型

  • 在GO中String类型可以存储任意字节,在编写代码过程,当定义好一个字符串时,存储的是utf-8编码后的字节, 也就是说以下的s和s1字符串是等价的
package main

import "fmt"

func main() {
	s := "你"
	s1 := "\xe4\xbd\xa0"
	if s == s1 {
		fmt.Println("s == s1")
	}
}

output

s == s1

可以看到 s字符串实际存储的是对‘你’字符utf-8编码后的字节,那么回到最开始的问题,当使用下标进行访问的时候,s[0]打印的应该是编码后的第一个字节

fmt.Printf("%x", s[0])

output

e4 //确实如猜测一样打印第一个字节

那么是如何解决这个问题,按字符来进行访问,而不是字节?

四、rune类型

4.1定义

在builtin/builtin.go文件中定义描述

// 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.
type rune = int32

主要作用是用来区分字符值和整数值

4.2 应用

4.2.1 将字符串转化为rune类型

package main

import "fmt"

func main() {
	s := "你好"
	s1 := []rune(s)
	fmt.Printf("字节个数: %d\n", len(s))
	fmt.Printf("字符个数: %d\n", len(s1))
}

output

字节个数: 6
字符个数: 2

4.2.2 range
因为在GO中utf-8是唯一的编码方式,因此在对字符串使用range遍历时,会对字符串使用utf-8进行解码,转化为rune类型输出

package main

import "fmt"

func main() {
	s := "你好"
	for _, c := range s {
		fmt.Printf("%s\n", string(c))
	}
}

output

你
好

五、参考资料

Strings, bytes, runes and characters in Go
utf-8编码介绍 wiki
Unicode介绍