【计算机学习笔记】GB2312、GBK、Unicode等字符编码的理解

之前编写win32程序时没怎么关注过宽字符到底是个啥东西,最近在编写网络框架又遇到字符相关的问题,所以写一篇文章记录一下(有些部分属于个人理解,如果有错误欢迎指出)

目录

  • 几个常见的编码方式
  • Unicode和UTF-8、UTF-16、UTF-32的关系
  • 字符编码的应用
    • 文本文件里的字符
    • 编程中的字符
      • 字符串字面量
      • 高级语言的窄字符

几个常见的编码方式

  • GB2312:早期的汉字编码,覆盖6000+个常用汉字,无法处理生僻字或者古文
  • GBK:收录20000+个汉字和符号,包括繁体字生僻字等
  • GB18030:较新的汉字字集,与 GB 2312-1980 和 GBK 兼容,共收录汉字 70000+ 个,采用多字节编码,每个字可以由 1 个、2 个或 4 个字节组成
    GB2312GBK均属于2字节定长编码,和ASCII混编,ASCII区字符固定占用1字节,汉字区字符固定占用2字节
  • Unicode:为世界上所有字符都分配了一个唯一的数字编号,目前编号范围从 0x000000 到 0x10FFFF,一共17个平面,每个平面有65536个码点

Unicode和UTF-8、UTF-16、UTF-32的关系

Unicode只规定了每个字符的编号,但没有规定二进制码如何存储,而UTF-8、UTF-16、UTF-32就是Unicode的二进制存储实现方案

  • UTF-8:使用变长编码,编号小的使用的字节就少,编号大的使用的字节就多。使用的字节个数从 1 到 4 个不等,实现了对 ASCII 码的向后兼容,网络传输一般选择这种方式节省网络资源。编码规则:
    1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
    2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
    3. 例如在U+0080U+07FF之间的字符,UTF - 8 用 2 个字节来编码。其格式为110xxxxx 10xxxxxx。编码时,将 Unicode 码点的二进制表示分为两部分,前 5 位放在第一个字节的xxxxx位置,后 6 位放在第二个字节的xxxxxx位置。
  • UTF-16:使用变长编码
    1. 对于编号在U+0000U+FFFF的字符(常用字符集),直接用两个字节表示。
    2. 编号在U+10000U+10FFFF之间的字符,需要用四个字节表示。
    3. UTF-16有字节的顺序问题(大小端),所以就有 UTF-16BE 表示大端,UTF-16LE 表示小端。
    4. 会在字符开头添加FEFF(不知道干什么用,网上也找不到资料)
  • UTF-32:定长编码,直接将码点转换为4字节的二进制表示形式,消耗较大,用得比较少,同样也有字节顺序问题

字符编码的应用

文本文件里的字符

  • ANSI:在一些文本编辑器里(例如记事本)会看到ANSI编码方式。ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码,例如中国的计算机ANSI编码即为GBK,美国的计算机ANSI编码即为ASCII
    如下图所示, 记事本和rider编辑器右下角都会有显示此文件的编码方式
    记事本
    rider

在这些文本编辑器里选择转换编码方式的话,则文本的内容不变,改变编码方式。选择重新加载,则内存内容不变,重新以新的编码方式解析成文本

下面展示分别使用ANSI(GBK),UTF-8,UTF-16,UTF-32四种方式存储“你好我是123456”这个字符串所需大小:

  1. ANSI(GBK):汉字占2字节,ASCII字符占1字节
    在这里插入图片描述
  2. UTF-8:汉字占3字节,ASCII字符占1字节
    在这里插入图片描述
  3. UTF-16:汉字占2字节,ASCII字符占2字节,UTF-16还有在开头添加的2字节
    在这里插入图片描述
  4. UTF-32:每个字符4字节,因为记事本没有UTF32,我在Rider修改编码方式
    在这里插入图片描述
    用VS打断点测试一下大端序UTF-16的内存情况,下图为文本文件存储的22字节内容:
    在这里插入图片描述
    除了开头添加的FEFF,“你好我是”这四个汉字的Unicode编号分别为
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    可以发现和内存里汉字的内容和字符编码相对应,后面的31003200这些就不一个个查了

编程中的字符

  • C/C++中窄字符和宽字符共用,窄字符即string(char),宽字符即wstring(wchar_t),Python/C#这种高级语言里的string默认为宽字符
  • 窄字符字符串以单个字节为单位,输出长度是输出字节数;宽字符字符串以字符为单位,输出长度是输出字符数

字符串字面量

C++中存储窄字符串字面量的话,字符串编码方式和代码文本文件的编码方式有关,存储宽字符串字面量的话要在字符串前面加‘L’标记,在Python/C#之类的高级语言里则是直接存储宽字符的字面量
例如下面这一段C++代码,如果文件格式为GBK,则输出14,如果为UTF-8,则输出18

#include <iostream>

int main()
{
    std::string str = "你好我是123456";
    std::cout << str.size();

    return 0;
}

下面是C++,Python,C#代码分别存储宽字符并输出大小的代码:

#include <iostream>

int main()
{
    std::wstring str = L"你好我是123456";
    std::cout << str.size();

    return 0;
}

Rider中的C++输出

s = "你好我是123456"
print(len(s))

Pycharm中的Python输出

using UnityEngine;

public class StartUp : MonoBehaviour
{
    private void Start()
    {
        string str = "你好我是123456";
        Debug.Log(str.Length);
    }
}

在这里插入图片描述

高级语言的窄字符

刚刚说了,Python/C#这种高级语言的字符串默认采用宽字符,如果要在高级语言使用窄字符,则需要对字符串使用encode之类的函数变成高级语言的byte数组

print(len("你好我是123456".encode("utf-8")))
print(len("你好我是123456".encode("gbk")))

在这里插入图片描述

using System.Text;
using UnityEngine;

public class StartUp : MonoBehaviour
{
    private void Start()
    {
        string str = "你好我是123456";
        
        byte[] utf8Bytes = Encoding.GetEncoding("UTF-8").GetBytes(str);
        byte[] gbkBytes = Encoding.GetEncoding("GBK").GetBytes(str);
        
        Debug.Log("UTF-8编码后的长度" + utf8Bytes.Length);
        Debug.Log("GBK编码后的长度" + gbkBytes.Length);
    }
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS 快速上手

目录 一. CSS概念 二. CSS语法 1. 基本语法规范 2. CSS的三种引入方式 (1) 行内样式 (2) 内部样式表 (3) 外部样式表 3. CSS选择器 (1) 标签选择器 (2) 类选择器 (3) id选择器 (4) 通配符选择器 (5) 复合选择器 <1> 空格 <2> 没有空格 <3> &q…

【时间之外】IT人求职和创业应知【60】-卡脖子

目录 新闻一&#xff1a;达成合作&#xff0c;将在中国推出生成式人工智能服务 新闻二&#xff1a;机器人新赛道 新闻三&#xff1a;简化用户信息获取流程&#xff0c;提升小程序体验 去年人口出生下降&#xff0c;3年以后&#xff0c;幼儿园要关闭很多&#xff0c;6年以后小…

centos9升级OpenSSH

需求 Centos9系统升级OpenSSH和OpenSSL OpenSSH升级为openssh-9.8p1 OpenSSL默认为OpenSSL-3.2.2&#xff08;根据需求进行升级&#xff09; 将源码包编译为rpm包 查看OpenSSH和OpenSSL版本 ssh -V下载源码包并上传到服务器 openssh最新版本下载地址 wget https://cdn.openb…

node.js中实现GETPOST请求

创建基本的服务器 const express require(express); const indexRouter require(./router); // 引入路由 const app express(); const port 3000; // 挂载路由 app.use(/api, indexRouter); app.listen(port, () > {console.log(Server is running on http://localhost…

shell 条件测试

一、命令执行结果判定 && &#xff1a; 在命令执行后如果没有任何报错时会执行符号后面的动作 || &#xff1a; 在命令执行后有报错执行符号后的动作 [rootlong ~]# a10 [rootlong ~]# echo $a 10 [rootlong ~]# [ $a -gt "5" ] && echo yes || e…

JS中的原型链与继承

原型链的类比 JS中原型链&#xff0c;本质上就是对象之间的关系&#xff0c;通过protoype和[[Prototype]]属性建立起来的连接。这种链条是动态的&#xff0c;可以随时变更。 这个就跟C/C中通过指针建立的关系很相似&#xff0c;比如&#xff0c;通过指针建立一个链表&#xf…

【Linux网络编程】第七弹---构建类似XShell功能的TCP服务器:从TcpServer类到主程序的完整实现

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、TcpServer.hpp 1.1、TcpServer类基本结构 1.2、 Execute() 2、Command.hpp 2.1、Command类基本结构 …

C语言控制语句与案例

控制语句与案例 1. 选择结构 1.1 if 语句 if 语句用于根据条件执行不同的代码块。最基本的语法形式如下&#xff1a; // 单分支 if (条件) {// 条件为真时执行的代码 }// 双分支 if (条件) {// 条件为真时执行的代码 } else {// 条件为假时执行的代码 }// 多分支 if (条件1…

【分子材料发现】——GAP:催化过程中吸附构型的多模态语言和图学习(数据集处理详解)(二)

Multimodal Language and Graph Learning of Adsorption Configuration in Catalysis https://arxiv.org/abs/2401.07408Paper Data: https://doi.org/10.6084/m9.figshare.27208356.v2 1 Dataset CatBERTa训练的文本字符串输入来源于Open Catalyst 2020 &#xff08;OC20…

SpringBoot自动配置底层核心源码

SpringBoot底层核心源码 一、工程创建二、进一步改造三、自动配置 探究SpringBoot的自动配置原理&#xff0c;我们可以自己写一个启动类的注解。 一、工程创建 首先创建一个工程&#xff0c;工程目录如下&#xff1a; 自定义一个启动函数&#xff1a; package org.springboo…

【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目之后端环境搭建

【Springboot3vue3】从零到一搭建Springboot3vue3前后端分离项目&#xff0c;整合knef4j和mybaits实现基础用户信息管理 后端环境搭建1.1 环境准备1.2 数据库表准备1.3 SpringBoot3项目创建1.4 MySql环境整合&#xff0c;使用druid连接池1.5 整合mybatis-plus1.5.1 引入mybatie…

【书生大模型实战营】Linux 基础知识-L0G1000

前言&#xff1a;书生大模型实战营是上海人工智能实验室开展的大模型系列实践活动&#xff0c;提供免费算力平台&#xff0c;学员通过闯关式任务&#xff0c;可获得免费算力和存储&#xff0c;助力项目实践。本期是第4期&#xff0c;时间从十一月份开始&#xff0c;持续到十二月…

JS进阶DAY3|事件(二)事件流

目录 一、事件流说明 1.1 事件流概念 1.2 事件捕获阶段 1.3 事件冒泡阶段 二、事件传播的两个阶段说明 2.1 事件捕获 2.2 事件冒泡 3.3 示例代码 三、阻止冒泡 四、事件解绑 4.1 removeEventListener方法 4.2 使用 DOM0 级事件属性 4.3 使用一次性事件监听器 一、…

【AI工具】强大的AI编辑器Cursor详细使用教程

目录 一、下载安装与注册 二、内置模型与配置 三、常用快捷键 四、项目开发与问答 五、注意事项与技巧 参考资料 近日&#xff0c;由四名麻省理工学院&#xff08;MIT&#xff09;本科生共同创立的Anysphere公司宣布&#xff0c;其开发的AI代码编辑器Cursor在成立短短两年…

【AWR软件】AWR 软件添加电磁结构

文章目录 前言步骤 前言 微波虚拟 实验 步骤 project -> add em struture -> new em structure 输入名称&#xff0c;create. 添加端口&#xff1a;add edge port

uni-app登录界面样式

非常简洁的登录、注册界面模板&#xff0c;使用uni-app编写&#xff0c;直接复制粘贴即可&#xff0c;无任何引用&#xff0c;全部公开。 废话不多说&#xff0c;代码如下&#xff1a; login.vue文件 <template><view class"screen"><view class"…

普通算法——一维前缀和

一维前缀和 题目链接&#xff1a;https://www.acwing.com/problem/content/797/ 题目描述&#xff1a; 输入一个长度为 n 的整数序列。接下来再输入 m 个询问&#xff0c;每个询问输入一对 l,r。对于每个询问&#xff0c;输出原序列中从第 l 个数到第 r 个数的和。 **什么是…

小程序项目的基本组成结构

分类介绍 项目根目录下的文件及文件夹 pages文件夹 用来存放所有小程序的页面&#xff0c;其中每个页面都由4个基本文件组成&#xff0c;它们分别是&#xff1a; .js文件&#xff1a;页面的脚本文件&#xff0c;用于存放页面的数据、事件处理函数等 .json文件&#xff1a;…

【Go 基础】并发相关

并发相关 CAS CAS算法&#xff08;Compare And Swap&#xff09;&#xff0c;是原⼦操作的⼀种,&#xff0c;CAS 算法是⼀种有名的⽆锁算法。⽆锁编程&#xff0c;即不使⽤锁的情况下实现多线程之间的变量同步。可⽤于在多线程编程中实现不被打断的数据交换操作&#xff0c;从…

【H2O2|全栈】Node.js与MySQL连接

目录 前言 开篇语 准备工作 初始配置 创建连接池 操作数据库 封装方法 结束语 前言 开篇语 本节讲解如何使用Node.js实现与MySQL数据库的连接&#xff0c;并将该过程进行函数封装。 与基础部分的语法相比&#xff0c;ES6的语法进行了一些更加严谨的约束和优化&#…