理解go字符编码和转换方式

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
性能测试 PTS,5000VUM额度
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 【7月更文挑战第2天】**Unicode是全球字符统一编码标准,包含110万个字符。它有多种编码实现,如UTF-8、UTF-16和UTF-32。UTF-8现为事实标准。Go语言源码默认采用UTF-8编码。**

简介

我如何知道要读取字符的字节数?
如果第一个字节的第一个位是 0,则它是单个字节。
如果第一个字节的前 3 位是 110,那么它有 2 个字节。
如果第一个字节的前 4 位是 1110,那么它有 3 个字节。
......
如果第一个字节的前 7 位为 1111110,则它有 6 个字节。

为什么字节 2 到 6 的前 2 位总是以 10 开头?
它用作标记,它指示这些字节是正在读取的字符的延续。没有这个,就无法区分这是一个新角色还是延续。

为了表示 2 个字节,为什么不在第一个字节中使用 11 而不是 110?

让我们假设我们没有 0,而是只有 11。如果第三位恰好是 1,我们如何将其与同样具有 111 的 3 字节的指示符区分开来。因此,我们需要有 0。

1 字符编码的统一:unicode 和 utf8

统一码又被称之为万国码 unicode,在1994年发布。此时人类终于有了收纳全部人造字符的统一字符集。

Unicode是Universal Multiple-Octet Coded Character Set 的缩写。 中文意思是 通用多字节编码字符集。

它是由一个名为Unicode学会,Unicode Consortium的机构制定的字符集系统。

Unicode字符集致力于为全世界线程每个语言的字符分配统一且唯一的字符编号,以满足跨语言,跨平台进行文本数据交换,处理,存储和显示。

    码点/序号          字符

    U+0000          .....
    ...
    U+4E2D           中
    ...
    U+10FFFF         ...

序号是全世界所有语言文字的符号分配的唯一编号。序号的范围从 0x000000 到0x10FFFF,全部可以容纳110多万个字符。

这个序号也被称之为Unicode码点。第二列字符就称为Unicode字符。

考虑到目前使用最多也就是最基础的ASCII字符集码点兼容性。前128个码点对应ASCII字符集。

现在Unicode字符集的码点表有了,只需要知道每个码点在计算机的内存编码表示,位模式。

我们知道ASCII字符集的内存编码表示位模式使用的是与其字符码点相同的数值,那么Unicode采用的是上面内存编码表示呢?

答案是并不唯一,常用的有三类:

    * UTF-16
    该方案使用2或4表示每个Unicode字符码点。它的优点是编码解码简单,因为全部字符都用偶数字节表示;

    其不足也很明显,比如存在字节序问题,不兼容ASCII字符内存表示以及空间效率不佳。

    * UTF-32
    该方案固定使用4字节表示每个Unicode字符码点。它的优点也是编解码简单,因为全部字符都用4字节表示。

            不足也和UTF-16一样明显,同样存在字节序的问题。 不兼容ASCII字符内存表示,且空间效率是这三个方案最差的。

    *UTF-8
    以其他的不同,UTF8使用变长字节对Unicode字符码点进行编码。

编码采用字节数量与Unicode字符在码点表的序号有关。

表示序号(码点)小的字符使用的字节少,表示序号(码点)大的字符使用的字节多。

2 理解UTF8编码

UTF8编码使用的字节从1到4不等。前128个与ASCII字符重合码点(U+0000 ~U+007F)使用1字节表示;

带变音符号的拉丁文,希腊文,西里尔阿拉伯文使用2字节表示,函数使用3字节表示,其他极少使用的语言使用4字节表示。

这样的编码方案是兼容ASCII字符内存表示的,采用UTF-8方案在内存表示Unicode字符时,已有的ASCII字符可以直接被作为Unicode字符进行存储和传输,无需改变。

此外,UTF8的编码单元为1字节,也就是一次编解码1字节,所以在处理UTF8方案表示的Unicode字符就不需要像UTF16或UTF32那样考虑字节序问题。

这三个方案中,UTF8方案空间效率最高。

我们分别使用这三个编码方式对 Unicode的字符 A 编码,LE表示小端字节库 Little Endian,BE 表示大端字节序 Big Endian

    Unicode  A
    Unicode 码点序号  0x000041
    UTF-8编码: 0x41
    UTF-16BE编码: 0xFEFF0041
    UTF-16LE编码: 0xFFFE4100
    UTF-32BE编码: 0x0000FEFF00000041
    UTF-32LE编码: 0xFFFE000041000000

由于UTF-16和UTF-32编码方案存在字节序问题,因此上面针对每个方案各自给出两个结果。

以UTF-16小端字节序结果0xFFFE4100为例,这个编码结果由4字节组成,前两个字节为0xFEFE,这个特定位模式时字节序标记(Byte Order Mark,BOM)。

Unicode规范对字节序标记约定如下:

    FF FE             UTF-16  小端字节序
    FE FF             UTF-16  大端字节序
    FF FE 00 00       UTF-32 小端字节序
    00 00 FE FF       UTF-32 大端字节序
    EF BB BF          UTF-8

如果没有提供字节序标记,则默认采用大端字节序解码。

另外我们注意到,Unicode 规范为UTF-8也准备了一个字节序标记 EF BB BF

但是由于UTF-8 没有字节序问题,因此这个BOM只是用于表明该数据流采用的为UTF-8编码方案,算是一个编码方案类型标记。

UTF-8编码方案由于优点众多,经过多年发展,已成为Unicode 字符在计算机中内存编码表示 位模式方案的事实标准。 Go运用顺应了这个趋势。源码文件的字符编码也是使用UTF8编码。

3 例子:在WEB编码中Content-Type 和 Meta 标记

在 Internet 中,为了使客户端和服务器正确通信,需要交换所使用的编码类型。
HTTP 协议有一个名为 content-type 的标头,可用于此目的。
内容类型:text/plain; charset=“UTF-8”。
如果 Web 服务器只处理一种类型的应用程序并且所有页面都使用相同的编码,则此操作正常。
如果 Web 服务器使用不同的编码处理多个应用程序,该怎么办?
HTML 有元标记,我们可以在这个标记中指定编码信息。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

4 Unicode 和 UTF-8相互转换

Unicode是一种在计算机上使用的字符编码。

它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

本质上Unicode表示了一种字符与二进制编码的一一对应关系,所以是一种单字符的编码。

  1. 对于ASCII(不包含扩展128+)字符,UTF-8编码、Unicode编码、ASCII码均相同(即单字节以0开头)

  2. 对于非ASCII(不包含扩展128+)字符,若字符有n个字节(编码后)。
    则首字节的开头为n个1和1个0,其余字节均以10开头。除去这些开头固定位,其余位组合表示Unicode字符。

转换(2+字节UTF-8)

UTF-8 to Unicode

    将UTF-8 按字节进行分割,以编码规则去掉每个字节头部的占位01,剩下位进行组合即Unicode字符

Unicode to UTF-8

    从低位开始每次取6位,前加10组成尾部一个字节。
    直到不足六位,加上对应的n个1和1个0,首字节的大端不足位补0,
    如补充字节后位数不够则再增加一字节,规则同上。

(按规则预估字节数,优先写好每个字节的填充位,从末端补充即可)

Go默认字符集Unicode以及采用编码方案UTF8,深入理解字符,字符集的属性,码点和内存编码表示以及它们之间的关系。

5 小结

Unicode是全球字符统一编码标准,包含110万个字符。
它有多种编码实现,如UTF-8、UTF-16和UTF-32。UTF-8现为事实标准,兼容ASCII,使用1-4字节编码字符,小字符用字节少,大字符用字节多。
UTF-16和UTF-32则固定2或4字节,但有字节序问题。
BOM用于标识字节序,但在UTF-8中仅作识别编码类型之用。Go语言源码默认采用UTF-8编码

目录
相关文章
|
6月前
|
Go
Go 语言输出文本函数详解
Go语言拥有三个用于输出文本的函数: Print() Println() Printf() Print() 函数以其默认格式打印其参数。
55 0
|
2月前
|
Go
Go字节数组与字符串相互转换
Go字节数组与字符串相互转换
36 3
|
26天前
|
PyTorch 算法框架/工具 数据格式
Python实用记录(八):不同格式之间的转换
本文介绍了Python中不同数据格式之间的转换方法,包括numpy数组与列表、字符串之间的转换,以及PyTorch张量与numpy数组之间的转换。
13 0
|
2月前
|
Go
Golang语言基本数据类型默认值及字符串之间互相转换案例
这篇文章讲解了Golang语言中基本数据类型的默认值、类型转换的概述以及整型、浮点型、字符串之间的相互转换案例,包括如何将基本数据类型转换为字符串类型和字符串类型转换为基本数据类型,以及字符串与字节切片之间的转换。
18 2
|
4月前
|
编译器 Go 开发者
Go中(_)字段有什么特殊用途?
在Go语言中,结构体`User`含`Name`和`Age`字段。不带下划线的结构体可以用位置或具名初始化。但若添加下划线字段`_`,仅能通过零值或具名初始化,因`_`是未导出字段,位置初始化会导致编译错误。这样设计可提高代码可读性和避免顺序错误。
|
6月前
|
存储 自然语言处理 算法
Tokenization 指南:字节对编码,WordPiece等方法Python代码详解
在2022年11月OpenAI的ChatGPT发布之后,大型语言模型(llm)变得非常受欢迎。从那时起,这些语言模型的使用得到了爆炸式的发展,这在一定程度上得益于HuggingFace的Transformer库和PyTorch等库。
166 3
|
11月前
|
JSON Go 数据格式
go 变量与json相互转换
go 变量与json相互转换
64 1
|
JSON 前端开发 Go
Go编程模式 - 2.基础编码下
尽量用`time.Time`和`time.Duration`,如果必须用string,尽量用`time.RFC3339`
29 0
|
编译器 Go C++
Go编程模式 - 1.基础编码上
Program to an interface, not an implementation
32 0
|
Go 索引 Python
python编码基础--字符串与它的相关操作
python编码基础--字符串与它的相关操作