浅谈Unicode与UTF-8

我们都知道,在Golang中字符都是以UTF-8编码的形式存储,当我们使用range遍历字符串的时候,go会为我们取出一个字符(rune)而不是一个byte,例如以下例子,我们使用range迭代取出第一个字符“你”,并且打印输出取出的字符编码以及内容,接着我们使用取址方法观察内存中实际存储的内容是什么。
在这里插入图片描述

先说结论:

迭代器取出的是字符的Unicode编码,而内存里实际存储的是UTF-8实现。
输出结果如下图所示:
在这里插入图片描述
我们可以发现,迭代器取出的内容与实际存储内容不一致,这是因为:迭代器取出的是字符的unicode编码,“你”在Unicode编码里是第20320位,而真正在计算机内的实现方法采用UTF-8编码方式,本文将详细解释如何实现unicode到UTF-8的转变。

Unicode

统一码(Unicode),也叫万国码、单一码,由统一码联盟开发,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。
统一码是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
统一码是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。统一码用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

为什么需要UTF-8?

我们已经有了Unicode编码,就有了一本字典,给每个字符一个编码,字符集序号一直从0-0x10FFFF。但是问题在于,单纯使用Unicode编码无法让计算机判断出哪里是一个字符,例如
00000001 00000001,计算机应该看成257还是两个1呢?这就涉及到如何实现变长编码,让unicode能够最大化利用计算机内存。现在普遍的实现方法就是UTF-8编码方式,将Unicode通过一定的转换方法变为UTF-8,使得计算机能够识别不定长的字符编码。

UTF-8编码规则

  1. 对于单字节的符号(英文字符),字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。如 A 在ASCII中是65,对应二进制 0100 0001
  2. 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

ASCII有128个字符,所以就是一个字节的后七位,第一位0代表单字节。

如果第一位是1,那么代表字节不完全,为多字节字符。计算机读取第一个字节的1个数,读到0时统计读到了多少个1,据此判断此字符几个字节。

那么为什么我们不直接用1开头表示多字节字符呢?为什么后续的字节开头需要使用10?

假设我们将后续字节设计为以1开头,那么UTF-8编码中的多字节字符的字节格式可能会产生冲突。例如,假设一个多字节字符的编码为:

110xxxxx 10xxxxxx

现在,如果后续字节以1开头,我们无法判断这个1是作为后续字节的一部分,还是作为下一个字符的起始字节。这会导致解析错误,无法正确识别字符的边界。

有人问,那我第一个字节都已经知道后面以后几个字节了,为什么还要用10开头呢,直接8bit全部用上不是更好吗?

UTF-8使用变长编码,这意味着字符占用的字节数是可变的。通过在第一个字节中指示字符占用的字节数,我们可以确定如何解析后续字节。然而,如果后续字节使用完整的8位来表示字符信息,会导致解码时的歧义和错误。

如果后续字节使用全部8位,就无法准确判断一个字节是属于哪个字符。通过将后续字节以"10"开头,我们可以明确地指示它们是后续字节,并且解码器可以根据这个特定的模式来解析UTF-8序列。这种设计保证了解码的自同步性,即即使在传输过程中发生了错误或数据丢失,解码器仍然能够正确地恢复每个字符的边界。

简单概括就是,即使丢掉了第一个字节的信息,后续也能根据每个字节的开头来判断处于哪个位置!

因此,为了明确表示多字节字符的后续字节,UTF-8编码规定后续字节必须以10开头。这样,我们在解析时可以准确地识别出多字节字符的起始和后续字节,避免了歧义和解析错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/7684.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

让你不再好奇音频转换格式软件免费有哪些

小美:你好,最近我需要将一些音频文件转换成其他格式,但是不知道常用的音频转换工具有哪些,你有什么建议吗? 李明:当然,有很多音频转换工具可以选择。建议你关注下这篇文章,我将通过…

【动手学习深度学习--逐行代码解析合集】06多层感知机的从零开始实现

【动手学习深度学习】逐行代码解析合集 06多层感知机的从零开始实现 视频链接:动手学习深度学习–softmax回归简洁实现 课程主页:https://courses.d2l.ai/zh-v2/ 教材:https://zh-v2.d2l.ai/ 1、多层感知机 2、从线性到非线性 3、激活函数 R…

ChatGPT应用工具推荐

ChatGPT作为一种先进的自然生成技术,已经在各个领域展现出了其强大的应用能力,下面将给大家介绍一些ChatGPT的功能应用。 简介 此系统是基于likeadmin—PHP开发的智能对话系统,ChatGPT是一种基于人工智能技术的聊天机器人,它可以…

亚马逊云科技推出Amazon AppFabric,SaaS安全不断加码

亚马逊云科技近日宣布推出Amazon AppFabric来增强公司在软件即服务(SaaS)应用程序方面的现有投入。Amazon AppFabric是一项无代码服务,可以为客户提高安全性,管理水平和生产力。只需在亚马逊云科技管理控制台上点击几下&#xff0…

机器学习之深度神经网络

目录 卷积神经网络与全连接神经网络 前向后向传播推导 通用手写体识别模型 人脸识别模型 电影评论情感分析模型 卷积神经网络与全连接神经网络 卷积神经网络(Convolutional Neural Network,CNN)和全连接神经网络(Fully Conn…

单片机STM32看门狗详解(嵌入式学习)

单片机STM32看门狗 什么是看门狗为什么需要看门狗?STM32CubeMX配置和应用示例独立看门狗(IWDG)窗口看门狗(WWDG) 注意事项 什么是看门狗 单片机STM32的看门狗(Watchdog)是一种硬件定时器&#…

动态ip与静态ip的概念、区别、应用场景

动态ip与静态ip的区别 前言一、介绍IP地址的概念和作用1.1、IP地址的定义1.2、IP地址的作用 二、动态IP和静态IP的区别2.1、动态IP和静态IP的定义2.2、动态IP和静态IP的特点2.3、动态IP和静态IP的优缺点比较 三、动态IP和静态IP的应用场景3.1. 动态IP的应用场景3.2. 静态IP的应…

SQL死锁

目录 前言: 分析: 死锁产生的原因: sql死锁 模拟: 解决办法: (本质:快速筛选或高效处理、以此减少锁冲突) ①大事务拆成小事务,尽可能缩小事务范围 大事务:将多个操作放在一个事务中执行…

SpringBoot - 在IDEA中经常发现:Could not autowire. No beans of ‘xxx‘ type found的错误

错误描述 在SPRINGBOOT的项目中,使用IDEA时经常会遇到Could not autowire. No beans of ‘xxxx’ type found的错误提示,但是程序的编译和运行都没有问题,这个错误提示并不影响项目的生产。 解决方案

Vue中如何进行状态持久化(LocalStorage、SessionStorage)

Vue中如何进行状态持久化(LocalStorage、SessionStorage)? 在Vue应用中,通常需要将一些状态进行持久化,以便在用户关闭浏览器或刷新页面后,仍能保留之前的状态。常见的持久化方式包括LocalStorage和Sessio…

深入理解 Golang: Channel 管道

Channel 的使用 Channel 声明方法 chInt : make(chan int) // unbuffered channel 非缓冲通道chInt : make(chan int, 0) // unbuffered channel 非缓冲通道chInt : make(chan int, 2) // bufferd channel 缓冲通道 Channel 基本用法 ch <- x // channel 接收数据 xx &l…

(免费分享)springboot,vue扫码点餐

系统前台客户端部署在微信小程序&#xff0c;主要面向的对象为到店点餐用户&#xff0c;我们要为买家提供一套完整的网上购物服务&#xff0c;内容包括扫码点餐、支付下单、凭取餐码取餐等。 系统后台客户端使用H5端&#xff0c;面向对象为在职员工&#xff0c;为员工提供各种…