首页 > 其他分享 >编码

编码

时间:2023-06-12 11:55:04浏览次数:37  
标签:编码 UTF 字节 字符 32 Unicode

一篇文章了解编码

因为最近在写代码和做一些渗透的时候经常遇到乱码的情况,而且原因各不相同,所以准备系统地学习一下编码的问题,以及实际中的应用。这篇文章是总结了网上的一些博客的内容完成的。

字符、字符集、字符编码

  • 字符:其实就是各种文字和符号的总成,可以是一个英文、一个汉字、一个标点,总之是一个符号。
  • 字符集:多个字符的集合,例如GB2312是中国国家标准的简体中文字符集,包含了6763个常用的汉字和字符
  • 字符编码:是一种映射规则,根据这个规则将字符映射为其他形式的数据方便在计算机中存储和使用。比如ASCII码用7个比特去编码所有的字符,将'A'编码为65进行存储,写入机器中就是01000001.常见的字符编码有UTF-8、GBK、Big5等

Unicode:UTF-8、UTF-16、UTF-32

在了解了上面字符集和字符编码的知识,我们要知道,Unicode是一个字符集,而像UTF-8才是真正的字符编码规则,UTF-8这些字符编码规则规定了用多少字节、是定长字节还是变长字节来映射Unicode中的字符。

Unicode

Unicode是国际标准字符集,它的目标是包含世界所有的文字和符号,它的字符集编码范围是0x0000-0x10ffff,现在的规模可以容纳100多万个符号。每个符号的编码都不同。

Unicode只是一个字符集,它只规定了符号的二进制代码,却没有规定这个二进制代码如何编码如何存储。

UTF-8

就像上文提到的,UTF-8是一种编码方式,用来将Unicode中的字符编码进行使用。并且UTF-8是使用最广的一种编码方式,UTF-16和UTF-32其实并不常见。

UTF-8的特点是对不同范围的字符使用不同长度的编码,是一种变长编码方式。长度是1~4个字节

UTF-8的编码规则记住两条:

  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的Unicode编码,所以我们可以知道,对于英文字母,UTF-8和ASCII码是相同的,(这也是因为英文字母是使用最多的字符,所以用最短的长度来表示可以最大程度地节省内存)
  • 对于n字节的符号(n>1),第一个字节的前n位设置为1,第n+1位设置为0,后面的所有字节的前两位一律设置为10。剩下的二进制位就是这个符号的Unicode编码

image-20230329114205103

image-20230329114205103

下面, 还是以汉字“严”为例,演示如何实现UTF-8编码。

已知“严”的unicode是\u4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

UCS-2和UCS-4

在区别UTF-16与UTF-32之前,我们要知道UCS-2和UCS-4,分别是用2个字节和4个字节来表示码点,也就是一个字符使用2个字节的二进制码还是4个字节的二进制码,还是没有定义字符的编码格式。

UTF-16

它使用UCS-2,将UCS-2规定的码点通过大端或小端的方式保存下来。UTF-16包括三种:UTF-16,UTF-16BE(Big Endian)和UTF-16LE(Little Endian)。UTF-16需要通过在文件开头以名为BOM(Byte Order Mark)的字符来表明文件是Big Endian还是Little Endian。

我们知道Unicode的范围为0x0~0x10FFFF,0x0!0xFFFF这段区间正好是16位也就是2字节。

0xFFFF~0x10FFFF这段,16位肯定存不下,所以就使用32位,也就是4字节,所以UTF-16的长度是2字节或者4字节。UTF-16的编码规则稍微复杂一点:

  • 对于 Unicode 码小于 0x10000 的字符, 使用 2 个字节存储,并且是直接存储 Unicode 码,不用进行编码转换
  • 对于 Unicode 码在 0x100000x10FFFF 之间的字符,使用 4 个字节存储,这 4 个字节分成前后两部分,每个部分各两个字节,其中,前面两个字节的前 6 位二进制固定为 110110,后面两个字节的前 6 位二进制固定为 110111, 前后部分各剩余 10 位二进制表示符号的 Unicode 码 减去 0x10000 的结果
  • 大于 0x10FFFF 的 Unicode 码无法用 UTF-16 编码

UTF-32

UTF-32使用4个字节表示码点,这样可以完全表示UCS-4的所有码点,不需要任何编码转换直接存储Unicode码,无需像UTF-8那样进行变长编码。

和UTF-16相似,UTF-32也区分UTF-32、UTF-32BE、UTF-32LE三种编码,也需要BOM字符

GB2312、GBK、GB18030

GB2312

1980 年,中国发布了第一个汉字编码标准,也即 GB2312 ,全称 《信息交换用汉字编码字符集·基本集》,通常简称 GB (“国标”汉语拼音首字母), 共收录了 6763 个常用的汉字和字符,此标准于次年5月实施,它满足了日常 99% 汉字的使用需求

编码方式:

  • 对于ASCII字符,使用1个字节存储,并且该字节最高位为0
  • 对于中国的字符,使用2个字节存储,并且规定每个字节的最高位为1

区位码

GB2312 对汉字进行了分区处理,每个区含有 94 个汉字或者字符,总共有 94 个区,每个汉字或者字符都对应一个 分区编号和分区内的位置编号,称为区位码

比如:汉字 "中" 字的 分区编号是 54,分区内位置编号是 48,所以,"中" 字的区位码是 54 48

国标码

国标码 也叫 交换码,用于交换文件所使用的编码,在早期,不同的操作系统可能使用不同的内码,如果它们之间要交换文件,则会发生乱码的现象,当时的解决方法是交换文件之前先转成交换码再交换,接收者收到之后再转成内码

ASICII 码为 0- 31 的这 32 个字符是不可显示的字符,为了避免和这些字符的码点冲突,将 分区编号和分区内位置编号都加上 32 ,把这个转换的结果称为 国标码

比如:汉字 "中" 字分区编号是 54,分区内位置编号是 48,加上 32 之后,分区编号是 54 + 32 = 86, ,分区内位置编号是 48 + 32 = 80,所以 "中" 字 的国标码是 86 80

内码

国标码 和 ASICII 码还是存在一定的重复,比如 "中" 字 的国标码是 86 80,对应第一个字节是 86,第二个字节是 80,而在 ASICII 码中它们分别代表大写字母V 和 大写字母 P,这就无法区分它们到底是一个汉字,还是两个字母

为了解决这一点,把国标码中的每个字节的最高位置为 1,也即相当于每个字节都加上 128 ( 2的7次方 ),还是以 "中" 字为例,它的 国标码是 86 80,加上 128 后, 第一个字节是 86 + 128 = 214, 第二个字节是 80 + 128 = 208,转化成 16 进制是 0xD6 0xD0 ( 214 的十六进制是 0xD6, 208 的十六进制是 0xD0 )

汉字的 区位码 + 32 + 128 就得到了内码,进一步简化,区位码 + 32 + 128 = 区位码 + 160 = 区位码 + 0xA0(128 的十六进制) , 因此 内码 = 区位码 + 0xA0

GBK

由于有些汉字是在 GB2312 标准发布之后才简化的,还有一些人名、繁体字、日语和朝鲜语中的汉字也没有包括在内,所以,在 GB2312 的基础上添加了这部分字符,就形成了 GBK ,全称 《汉字内码扩展规范》,共收录了两万多个汉字和字符,它完全兼容 GB2312

和 GB2312 一样,GBK 也是双字节编码

GB18030

GB18030 全称《信息技术 中文编码字符集》 ,共收录七万多个汉字和字符, 它在 GBK 的基础上增加了中日韩语中的汉字 和 少数名族的文字及字符,完全兼容 GB2312,基本兼容 GBK

与 GBK 不同的是,GB18030 是变长多字节字符集,每个字或字符可以由一个,两个或四个字节组成,所以它的编码空间是很大的,最多可以容纳 161 万个字符

ANSI

ANSI并不是某一种特定的字符编码,而是在不同系统中,ANSI表示不同的编码

ANSI是一种字符代码,为使计算机支持更多语言,通常使用 0x00~0x7f 范围的1 个字节来表示1个英文字符。超出此范围的使用0x80~0xFFFF来编码,即扩展的ASCII编码

比如:在简体中文Windows操作系统中,ANSI编码代表GBK编码,在繁体中文Windows操作系统中,ANSI编码代表Big5,在日文Windows操作系统中,ANSI代表JIS编码。

不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。ANSI编码表示英文字符时用一个字节,表示中文用两个或四个字节。

Big-5

在中国台湾、中国香港、中国澳门地区普遍使用繁体中文的情况下,当地电脑软件或操作系统经常使用Big5(又称大五码)作为繁体中文的默认文字编码。

同GBK编码一样,Big5编码也是采用双字节编码,兼容ASCII码。也就是说每个繁体中文汉字在Big5下占据2字节。

相关知识

宽字符和窄字符(多字节字符)

有的编码方式采用 1~n 个字节存储,是变长的,例如 UTF-8、GB2312、GBK 等;如果一个字符使用了这种编码方式,我们就将它称为多字节字符,或者窄字符。

有的编码方式是固定长度的,不管字符编号大小,始终采用 n 个字节存储,例如 UTF-32、UTF-16 等;如果一个字符使用了这种编码方式,我们就将它称为宽字符。

全角和半角

GB2312编码表有个值得注意的点,这个表中也有一些数字和字母,与ASCII里面的字母非常像。例如A3B2对应的是数字2(如下图),但是ASCII里面50(十进制)对应的也是数字2。他们的区别就是输入法中所说的“半角”和“全角”。全角的数字2占两个字节。

Windows系统如何区分ANSI背后的真实编码

微软用一个叫“Windows code pages”(在命令行下执行chcp命令可以查看当前code page的值)的值来判断系统默认编码,比如:简体中文的code page值为936(它表示GBK编码,win95之前表示GB2312),繁体中文的code page值为950(表示Big-5编码)

我们可以通过cmd命令修改当前终端的ANSI值:

chcp 437 //ANSI
CHCP 936 //gbk

执行chcp 437:

image-20230329172644817

image-20230329172644817

执行chcp 936:

image-20230329172711878

image-20230329172711878

chcp命令只改变当前终端的编码,并不影响系统默认的ANSI编码。

Windows下code page是根据当前系统区域(locale)来设置的,要想修改系统默认的“ANSI编码”,我们可以通过修改系统区域来实现(“控制面板” =>“时钟、语言和区域”=>“区域和语言”=>“管理”=>“更改系统区域设置...”):

image-20230329172928975

image-20230329172928975

ps:(如果一个APT组织针对某一国家某一地区进行精确打击,就可以通过ANSI编码来确定机器的国家,从而选择是否进行网络攻击)

烫烫烫与锟斤拷

手持两把锟斤拷,口中疾呼烫烫烫。脚踏千朵屯屯屯,笑看万物锘锘锘

这个段子就是将编码错误,从而导致乱码的常见情况,都是Unicode和GBK编码的转换错误。

对于VCS的编译器,分配空间后总要在里面填一些东西。默认填入的东西是这样的:

未分配或静态分配而未赋初值的内存空间,初值用0xCC填充,如不小心访问了它们,则会看到如下内容:

按字符输出为烫(0xCCCC)

按int输出为-858993460(0xCCCCCCCC)

动态分配(new,malloc)而未赋初值的内存空间,用0xCD填充,如不小心访问了它们,则会看到如下内容:

按字符输出为屯(0xCDCD)

按int输出为-842150451(0xCDCDCDCD)

锟斤拷则涉及Unicode的字符集转换问题,Unicode和老编码体系的转化过程中,肯定有一些字,用Unicode是没法表示的,Unicode官方用了一个占位符来表示这些文字,这就是:U+FFFD

U+FFFD的UTF-8编码是0xEFBFBD,如果重复多次形成:EFBFBDEFBFBDEFBFBD 。

在GBK/CP936/GB2312/GB18030的环境中显示的话,一个汉字2个字节,最终的结果就是:锟斤拷——锟(0xEFBF),斤(0xBDEF),拷(0xBFBD)。

出现锘锘锘的情况应该是BOM出了问题,因为锘的编码就是EFBB,BOM在UTF-16中本来是FFFE,到UTF-8就变成了EFBBBF,这个问题就是因为UTF-8没有BOM

标签:编码,UTF,字节,字符,32,Unicode
From: https://www.cnblogs.com/sca1p31/p/17474637.html

相关文章

  • idea java项目中,中文显示成Unicode(UTF-16编码)的字符,修改为中文显示
    idea选择File选择Setings搜索框搜索fileencodings勾选Transparentnative-to-asciiconversion      ......
  • python编码decode和encode
                文章来源:https://www.cnblogs.com/skyflask/p/7622991.html ......
  • 信道编码的基本概念
    本专栏包含信息论与编码的核心知识,按知识点组织,可作为教学或学习的参考。markdown版本已归档至【Github仓库:<https://github.com/timerring/information-theory>】或者公众号【AIShareLab】回复信息论获取。信道编码1.信道编码在通信系统中的位置和作用2.信道编码的基本分类:分......
  • 计算机网络中的曼彻斯特编码
    曼彻斯特编码是开放系统互连[OSI]的物理层用于对同步位流的时钟和数据进行编码的一种同步时钟编码技术。RZ的想法和L的想法在曼彻斯特结合数据通信采用不同的编码技术,保证数据安全和传输速度。曼彻斯特编码是数字编码的一个例子。由于每个数据位长度都是默认定义的,因此它与其他数......
  • 信道容量与香农定理、信源编码、信道编码总结
    1信道容量定义1.1信道容量:信道中平均每个符号所能传递的最大互信息量$I(X;Y)$$C=\mathop{max}\limits_{p(x)}{I(X;Y)}$单位:bit/符号1.2单位时间t内信道容量:$C_t=\frac{C}{t}$单位:bit/s1.3最佳输入概率$p(x)$分布时,传输的信息能达到信道容量1.4信道容量反映信道特性,表示信......
  • 计算机字符编码详解
    转自阿里云社区:https://developer.aliyun.com/article/1060857?spm=a2c6h.12873639.article-detail.38.4b5972357GYIBO版权声明:链接内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。......
  • H264/H265编码
    1、通常在处理音视频数据时,我们如何选择解码器?    通常我们不是根据NALU裸流数据中的信息来选择解码器,而是根据媒体封装层的信息来确定解码器。媒体封装层是表示媒体数据是什么封装格式的,比如MP4、FLV。在这层信息里,通常会携带码流编码格式的信息。拿MP4来说,我们可以......
  • java编码规范
     是从我的word文档里面直接拷贝出来的,某些地方排版好像不太对,懒得修改了,有不对的地方请指出,看到的话就会修改的。仅供参考,请勿盗取,谢谢。Java开发规范1.引言22.文件23.命名规则33.1基本的规则33.2常量命名33.3变量命名43.4方法命名53.5类和接口的命名53.6包的命名64.注......
  • Google C# 编码规范
    Refhttps://google.github.io/styleguide/csharp-style.htmlhttps://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines......
  • 前端常见的字符编码方案
    在前端开发中,最常见的字符编码方案是UTF-8。UTF-8是一种可变长度的Unicode编码方案,可以表示几乎所有的字符,并且与ASCII兼容。由于互联网的广泛应用和多语言的支持,UTF-8成为了前端开发中的首选字符编码方案。使用UTF-8编码的好处:1.多语言支持:UTF-8可以表示世界上几乎......