美文网首页
go之UTF-8

go之UTF-8

作者: killtl | 来源:发表于2022-01-06 13:26 被阅读0次

unicode

请先查看 字符编码笔记:ASCII,Unicode 和 UTF-8

go的字符串是如何编码的

根据golang官方博客https://blog.golang.org/strings的原文:

Go source code is always UTF-8.
A string holds arbitrary bytes.
A string literal, absent byte-level escapes, always holds valid UTF-8 sequences.

大致意思如下:

  • go中的代码总是用UTF-8编码,并且字符串能够存储任何字节
  • 没有经过字节级别的转义,那么字符串是一个标准的utf8序列

byte和rune

在Go语言中,一个string类型的值既可以被拆分为一个包含多个字符的序列([]rune),也可以被拆分为一个包含多个字节的序列([]byte)

rune是Go语言特有的一个基本数据类型,它的一个值就代表一个字符,即:一个Unicode字符。比如,'G'、'o'、'爱'、'好'、'者'代表的就都是一个个Unicode字符。rune的底层表达使用的是Unicode代码点,底层的存储用UTF-8编码

通过unicode部分我们已经知道,UTF-8编码方案会把一个Unicode字符编码为一个长度在[1, 4]范围内的字节序列。所以rune类型的值也可以由一个或多个字节来代表。

type rune = int32 //rune实际上就是int32类型的一个别名类型

举几个栗子

string转[]byte/[]rune
str := "Go爱好者"
fmt.Printf("  => runes(char): %q\n", []rune(str))
fmt.Printf("  => runes(hex): %x\n", []rune(str))
fmt.Printf("  => bytes(hex): [% x]\n", []byte(str))

// output
=> runes(char): ['G' 'o' '爱' '好' '者']  //这里用%q来安全的转义成单引号围绕的字符字面值,%s无法转义成字符字面值
=> runes(hex): [47 6f 7231 597d 8005]
=> bytes(hex): [47 6f e7 88 b1 e5 a5 bd e8 80 85]

分析:

  • []rune中的前两个元素即47和6f与[]byte中的前两个元素是一致的,因为UTF-8是兼容ASCII的,都用一个字节表示
  • []rune中的后三个元素分别对应[]byte中的后九个元素,其中连续的三个对应[]rune中的一个,因为rune中的中文字符使用UTF-8编码,占用三个字节,同时也是UTF-8编码对应Unicode码点

如下是Unicode编码中UTF-8的编码规则

Unicode编码(十六进制) UTF-8 字节流(二进制)
000000-00007F   0xxxxxxx
000080-0007FF   110xxxxx 10xxxxxx
000800-00FFFF   1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

'爱'为例,其对应的Unicode编码是16进制的7231,对应二进制111001000110001, 那怎么对应上[]byte中的e7 88 b1呢?
这里有一个转换过程,如下:

  • 因为0x010000> 0x7231 > 0x07FF,所以套用UTF-8的模板是1110xxxx 10xxxxxx 10xxxxxx
  • 根据模板中x数量对特殊字符的高位补0。x的数量是16,所以需要对111001000110001的高位补1个0,此时特殊字符的二进制表示为:0111001000110001
  • 模板中包含x的有3个部分,且长度分别是4、6和6,所以0111001000110001由底位向高位分别截取6、6和4位,得到1100010010000111
  • 将得到的截取位依次填充至模板,可得到UTF-8的完整二进制序列为:11100111 10001000 10110001,也就对应上了e7 88 b1
整数转string

通过上面已知,'爱'的Unicode编码对应16进制是7231,换算成整数就是29233

fmt.Printf("%q\n", 29233)
// output
'爱'

所以我们如果对整数进行强制转换成string,需要注意是否是对应的合法的Unicode码点

str := string(235234234234)
fmt.Printf("%q\n", str)
// output
"�"

这里因为235234234234不是合法的Unicode码点,所以强制转换后的结果是非预期的

for...range处理字符串

见代码:

str := "go,你好"
for i, v := range str  {
    fmt.Printf("%d %q\n", i, v)
}
// output
// 注意这里输出的索引值是以字节为跨度计算的
0 'g'
1 'o'
2 ','
5 '你'
8 '好'

带有range子句的for语句会先把被遍历的字符串值拆成一个字节序列,然后再试图找出这个字节序列中包含的每一个UTF-8编码值,或者说每一个Unicode字符

相关文章

  • go之UTF-8

    unicode 请先查看 字符编码笔记:ASCII,Unicode 和 UTF-8[https://www.rua...

  • 区块链开发之Go语言—字符串和字节

    字符串与字节的关系 Go 代码使用 UTF-8 编码,字符串和字节之间的转换依据的是UTF-8编码。注意中文是3个...

  • Go 的 UTF-8 实现

    计算机刚开始诞生的时候,计算机内的字符可以全部由 ASCII 来表示,ASCII 字符的长度是 7 位,可以表示 ...

  • golang内存逃逸

    一篇很好的博客: Go 语言机制之栈与指针 Go 语言机制之逃逸分析 Go 语言机制之内存剖析 Go 语言机制之数...

  • Go基本概念

    编码 Go默认支持UTF-8编码 声明变量 var vname1, vname2, vname3 type var...

  • 17-Go语言字符串和正则表达式

    字符串相关方法 获取字符串长度注意: Go语言编码方式是UTF-8,在UTF-8中一个汉字占3个字节 如果字符串中...

  • Go实战--golang中使用JWT(JSON Web Toke

    Go实战--golang中使用JWT(JSON Web Token) 生命不止,继续 go go go !!! 之...

  • Go 简明教程 三步走 初级篇

    编程,从 Hello World 开始。 Go 变量之随意变 Go常量之不可变 Go 函数定义 "返回参数列表" ...

  • go 字符串的遍历

    一 go字符串简介 在go 语言中字符串是一个不可变的字节序列,最基本的组成元素的字节,并且使用UTF-8的编码方...

  • 文章目录

    Go 源码解读篇 《Go源码解读篇》之常见数据结构(list) 《Go源码解读篇》之 Error 工作中知识总结 ...

网友评论

      本文标题:go之UTF-8

      本文链接:https://www.haomeiwen.com/subject/yqnlcrtx.html