龙空技术网

golang 字符类型--byte和rune

寒笛过霜天 185

前言:

而今你们对“c语言x41什么意思”可能比较关心,咱们都需要剖析一些“c语言x41什么意思”的相关资讯。那么小编也在网络上搜集了一些对于“c语言x41什么意思””的相关资讯,希望各位老铁们能喜欢,看官们一起来了解一下吧!

字符串中的每一个元素叫做"字符"。在遍历或者单个获取字符串元素时可以获得字符。严格来说, 这并不是 Go语言的一个类型, 字符只是整数的特殊用例。

Go语言的字符有以下两种:

一种是 uint8 类型, 或者叫 byte 型, 代表了 ASCII 码的一个字符。

另一种是 rune 类型, 代表一个 UTF-8 字符。当需要处理中文、日文或者其他复合字符时, 则需要用到 rune 类型。rune 类型实际是一个 int32。

byte 类型是 uint8 的别名, 对于只占用 1 个字节的传统 ASCII 编码的字符来说, 完全没有问题。例如:var ch byte = 'A';字符使用单引号括起来。

在 ASCII 码表中, A 的值是 65, 而使用 16 进制表示则为 41, 所以下面的写法是等效的:

var ch byte = 65 或 var ch byte = '\x41' //(\x 总是紧跟着长度为 2 的 16 进制数)

当需要处理中文、日文或者其他复合字符时, 则需要用到rune类型。rune类型实际是一个int32。

Go 使用了特殊的 rune 类型来处理 Unicode, 让基于 Unicode的文本处理更为方便, 也可以使用 byte 型进行默认字符串处理, 性能和扩展性都有照顾

package main

import (

"fmt"

)

// 遍历字符串

func main() {

s := "pprof.cn博客"

for i := 0; i < len(s); i++ { //byte

fmt.Printf("%v(%c) ", s[i], s[i])

}

fmt.Println()

for _, r := range s { //rune

fmt.Printf("%v(%c) ", r, r)

}

fmt.Println()

}

输出结果

112(p) 112(p) 114(r) 111(o) 102(f) 46(.) 99(c) 110(n) 229(å) 141() 154(š) 229(å) 174(®) 162(¢)

112(p) 112(p) 114(r) 111(o) 102(f) 46(.) 99(c) 110(n) 21338(博) 23458(客)

因为UTF8编码下一个中文汉字由3~4个字节组成, 所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果。

字符串底层是一个byte数组, 所以可以和[]byte类型相互转换。字符串是不能修改的 字符串是由byte字节组成, 所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符, 一个rune字符由一个或多个byte组成。

要修改字符串, 需要先将其转换成[]rune或[]byte, 完成后再转换为string。无论哪种转换, 都会重新分配内存, 并复制字节数组。

package main

import (

"fmt"

)

// 遍历字符串

func main() {

s1 := "hello"

// 强制类型转换

byteS1 := []byte(s1)

fmt.Println(byteS1)

byteS1[0] = 'H'

fmt.Println(string(byteS1))

s2 := "博客"

runeS2 := []rune(s2)

fmt.Println(runeS2)

runeS2[0] = '狗'

fmt.Println(string(runeS2))

}

输出结果:

[104 101 108 108 111]

Hello

[21338 23458]

狗客

不过 Go 同样支持 Unicode(UTF-8), 因此字符同样称为 Unicode 代码点或者 runes, 并在内存中使用 int 来表示。

在文档中, 一般使用格式 U+hhhh 来表示, 其中 h 表示一个 16 进制数。其实 rune 也是 Go 当中的一个类型, 并且是 int32 的别名。

在书写 Unicode 字符时, 需要在 16 进制数之前加上前缀 \u 或者 \U。

因为 Unicode 至少占用 2 个字节,所以我们使用 int16 或者 int 类型来表示。

如果需要使用到 4 字节, 则会加上 \U 前缀;前缀 \u 则总是紧跟着长度为 4 的 16 进制数, 前缀 \U 紧跟着长度为 8 的 16 进制数。

var ch int = '\u0041'

var ch2 int = '\u03B2'

var ch3 int = '\U00101234'

fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer

fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character

fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes

fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point

var ch int32 = '\u0041'

var ch2 int32 = '\u03B2'

var ch3 int32 = '\U00101234'

fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer

fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character

fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes

fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point

var ch rune = '\u0041'

var ch2 rune = '\u03B2'

var ch3 rune = '\U00101234'

fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer

fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character

fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes

fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point

以上输出的结果是一样的

65 - 946 - 1053236

A - β -

41 - 3B2 - 101234

U+0041 - U+03B2 - U+101234

【实例】: 字符与字符串之间的转换

package main

import (

"fmt"

"reflect"

"unicode/utf8"

)

func main() {

s := "Yes我爱慕课网!"

fmt.Println(len(s)) //19

fmt.Printf("%X\n", []byte(s)) //596573E68891E788B1E68595E8AFBEE7BD9121

for _, b := range []byte(s) {

fmt.Printf("%X ", b)

}

fmt.Println()

//输出结果: 59 65 73 E6 88 91 E7 88 B1 E6 85 95 E8 AF BE E7 BD 91 21

for i, ch := range s { //ch is a rune

fmt.Printf("(%d, %X) ", i, ch)

fmt.Printf("%s", reflect.TypeOf(ch)) // int32

}

//输出结果: (0, 59) (1, 65) (2, 73) (3, 6211) (6, 7231) (9, 6155) (12, 8BFE) (15, 7F51) (18, 21)

fmt.Println()

//输出字符串的长度

fmt.Println("Rune count:", utf8.RuneCountInString(s)) //Rune count: 9

bytes := []byte(s)

for len(bytes) > 0 {

ch, size := utf8.DecodeRune(bytes)

bytes = bytes[size:]

fmt.Printf("%c ", ch)

}

//输出结果: Y e s 我 爱 慕 课 网 !

fmt.Println()

for i, ch := range []rune(s) {

fmt.Printf("(%d, %c) ", i, ch)

}

fmt.Println()

//输出结果: (0, Y) (1, e) (2, s) (3, 我) (4, 爱) (5, 慕) (6, 课) (7, 网) (8, !)

}

【实例】: 字符与字符串之间的关系

package main

import "fmt"

func main() {

// 中文字符 Unicode CodePoint(码点) UTF8编码

// 中 U+4E2D E4B8AD

// 国 U+56FD E59BBD

// 欢 U+6B22 E6ACA2

// 迎 U+8FCE E8BF8E

// 您 U+60A8 E682A8

s := "中国欢迎您"

rs := []rune(s)

sl := []byte(s)

for i, v := range rs {

var utf8Bytes []byte

for j := i * 3; j < (i+1)*3; j++ { //汉字相当于三个字节

utf8Bytes = append(utf8Bytes, sl[j])

}

fmt.Printf("%s => %X => %X\n", string(v), v, utf8Bytes)

}

}

输出结果:

中 => 4E2D => E4B8AD

国 => 56FD => E59BBD

欢 => 6B22 => E6ACA2

迎 => 8FCE => E8BF8E

您 => 60A8 => E682A8

string、[]byte、rune 之间转换, 以及数据类型占用字节大小

package main

import (

"fmt"

"unsafe"

)

func main() {

/*

len 代表数据字节大小 如: len("abcd") 为 4 个字节 (英文一个字符一个字节, 中文一个字符三个字节)

Sizeof 代表的是数据类型所占字节大小, int64 数据类型所占空间 8 个字节

*/

var ch rune = '\u0041'

// fmt.Println(len(ch)) Error: invalid argument ch (type rune) for len 注意: len 不能用于 rune 类型

fmt.Println(unsafe.Sizeof(ch)) // 4 rune 类型 占用 4个字节

// rune 转换 为 string 方法

fmt.Println(string(ch)) // A

var by []byte = []byte{65}

fmt.Println(len(by)) // 1 占用1个字节

fmt.Println(unsafe.Sizeof(by)) // 24 []byte 类型 占用24个字节

// []byte 转换为 string 方法

fmt.Println(len(string(by))) // 1 占用1个字节

fmt.Println(unsafe.Sizeof(string(by))) // 16 string 类型 占用 15个字节

fmt.Println(string(by)) // A

}

标签: #c语言x41什么意思 #c语言中x41是什么意思