已知英文字母的ASCII 码值为108,那么英文字母i的ASC码值是? 20
1个回答
2022-03-20
展开全部
编码就是要数字化。
最简单的编码就是用流水号,但是流水号通常不方便使用(包括不方便数据处理),没有考虑类别划分(大类、中类、小类)的规律性。
数字化还要考虑存储,存储只能使用有限字长,且需要考虑尽量节省存储位。
描述CPU功能的编码方案有各种指令集。 整数的编码方案有原码、补码; 浮点数的编码方案有IEEE754,包括阶码(移码); 位图可以用位来表示颜色信息,有相应的编码和压缩方案; 音频可以采样声波的振动频率来数字化,两样有相应的编码和压缩方案,视频也是如此。
电子计算机是二进制的,编码使用二进制数字,要编码的对象有多少?就要考虑使用多少个二进制位。例如全球有70多亿人口(假设75亿),如果用二进制位给每人一个编号,需要多少个二进制位?就是2的多少次幂等于75亿,是一个对数的计算。log2(7500000000)≈32.8,用33个二进制位就够了。
这里要说的是字符的编码方案。
1 ASCII
英文字符数量少,用7个二进制就够了,但电脑的数据读写的二进制通常使用2的整数倍,就用了8个位,首位用零填充。美国人就搞了个英文字符的编码方案,称为ASCII。编码了128个字符,这100多个字符大部分都可以直接映射到键盘,可以直接输入。
void printAscii(){ for(int i=1;i<=128;i++) { if(i==10 || i ==13) printf("\"); else printf("%3d %c\",i,i); if(i%8==0) printf("\"); }}
虽然只有100多个字符,但其ASCII编码也是极其有规律性的,考虑到了尽可能方便数据处理。如:
大写字母的'A'的编码是是65,其编码是01000001,也就是十进制的12^6+1,
大写字母的'a'的编码是是97,其编码是01100001,也就是十进制的2^6+2^5+1;
大小写如何转换?差别只有第3位。大写转小写,只需要按位转换这个位就行了。
char toLower(char ch){ return ch | 1<<5;}char toUpper(char ch){ return ch & ~(1<<5);} 2 扩展ASCII
英语用 128 个字符来编码完全是足够的,但是用来表示其他语言,128 个字符是远远不够的。于是,一些欧洲的国家就决定,将 ASCII 码中闲置的最高位利用起来,这样一来就能表示 256 个字符。
3 GB2312和BGK
ASCII 码的问题在于尽管所有人都在 0 - 127 号字符上达成了一致,但对于 128 - 255 号字符上却有很多种不同的解释。与此同时,亚洲语言有更多的字符需要被存储,一个字节已经不够用了。于是,人们开始使用两个字节来存储字符。
等中国人们得到计算机时,已经没有可以利用的字节位来表示汉字,况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民,我们不客气地把那些127号之后的奇异符号们直接取消掉,规定一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。 中国人民看到这样很不错,于是就把这种汉字方案叫做 “GB2312“。GB2312 是对 ASCII 的中文扩展。
void printGB2312(){int i,j,sum=0;for(i=0xA1;i<0xAA;i++){for(j=0xA1;j<0xFF;j++) { printf("%c%c",i,j); sum++; }}for(i=0xB0;i<0xF8;i++){for(j=0xA1;j<0xFF;j++) { printf("%c%c",i,j); sum++; } } printf("\合计:%d\",sum); // 7614}
但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来。于是我们不得不继续把 GB2312 没有用到的码位找出来老实不客气地用上。 后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK包括了GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。 后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK扩成了 GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。 中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 “DBCS“(Double Byte Charecter Set 双字节字符集)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处 理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。那时候凡是受过加持,会编程的计算机僧侣 们都要每天念下面这个咒语数百遍: “一个汉字算两个英文字符!一个汉字算两个英文字符……”
void printGBK(){ int sum = 0; FILE * fp; fp = fopen("d:\\\\GBK.txt","w");int i,j;for(i=0x81;i<0xFF;i++){for(j=0x40;j<0x7F;j++){printf("%c%c",i,j); fprintf(fp,"%c%c",i,j); sum++;}for(j=0x80;j<0xFF;j++){printf("%c%c",i,j); fprintf(fp,"%c%c",i,j); sum++;}printf("\");} printf("\合计:%d\",sum); // 23940 fclose(fp); system("d:\\\\GBK.txt"); }
4 Unicode和UCS-2、UCS-4
因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,连大陆和台湾这样只相隔了150海里,使用着同一种语言的地区,也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字,就必须装上一个”汉字系统”,专门用来处理汉字的显示、输入的问题,如果装错了字符系统,显示就会乱了套!这怎么办?而且世界民族之林中还有那些一时用不上电脑的穷苦人民,他们的文字又怎么办?
一个叫 ISO (国际标谁化组织)的国际组织决定着手解决这个问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号的编码!称为“Universal Multiple-Octet Coded Character Set”,简称 UCS,俗称 “unicode”。
UCS-2 采用 16 位存储空间,两个字节编码每个字符,而 UCS-4 采用 4 个字节(实际上只用了 31 位,最高位必须为 0)编码。UCS-2 有 2^16=65536 个码位,UCS-4 有 2^31=2147483648 个码位。
对于ASCII里的那些“半角”字符,unicode包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。
UCS-4 根据最高位为 0 的最高字节分成 27=128 个组(group)。每个组再根据次高字节分为 256 个平面(plane)。每个平面根据第 3 个字节分为 256 行 (rows),每行包含 256 个单元(cells)。当然同一行的单元只是最后一个字节不同,其余都相同。
ISO 只用到 17 个平面,包含 1 个基本平面(BMP)和 16 个辅助平面,最高码位 U+10FFFF。
0 组的 0 号平面被称作 Basic Multilingual Plane,即基本多文种平面,简写 BMP。可知 BMP 区域内的字符只使用了两个字节,码位从 U+0000 至 U+FFFF。它实际上就是 UCS-2 的全部编码范围,后来因为码位不够用才扩展为 UCS-4。
5 多字节字符的输入、输出
例如汉字,键盘只有100多个按键?如何输入汉字?
现在我们使用的各种中文输入法(搜狗拼音输入法,王码输入法)就是中文输入的编码方案。不要看我们现在有各种方便快捷的输入法,最初可是一个老大难问题。
汉字的输出其实就是点阵图形的输出,也就是所谓的字库。
6 多字节字符的存储和读取几个字节做为一个字节编码的问题
Unicode和UCS-2、UCS-4的编码方案,就同时考虑了存储的问题。即要方便存储空间的节约(排在前面的编码可以使用较少的位来存储,排在后面的编码需要使用较多的位来存储)。
UTF-8、UTF-16、UTF-32就是UCS-4存储方案的实现。
unicode在很长一段时间内无法推广,直到互联网的出现,为解决unicode如何在网络上传输的问题,于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。UTF-8就是在互联网上使用最广的一种unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。
与此同时,文件通过文件头(无数据))来标识字符的编码的类型:
Windows使用代码页(code page)来适应各个国家和地区。code page可以被理解为内码。GBK对应的code page是CP936。可以CMD窗口中使用chcp命令来查看,或右击查看属性。 使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。 在bat中使用重定向来生成文本文件时,第一行可以声明chcp 65001,文件对应的存储方案就是utf-8。
对于文件内的字符,按文件头标识的编码方案来解释,对于定长的ASCII和UTF-32,可以使用定长的字节数来表示一个字符。
对于不定长的UTF-8,其每个字节的前几位都特意做了固定编码,用来识别一个字符需要读取几个字节。
UTF-16 的编码长度要么是 2 个字节(U+0000 到 U+FFFF),要么是 4 个字节(U+010000 到 U+10FFFF)。那么问题来了,当我们遇到两个字节时,到底是把这两个字节当作一个字符还是与后面的两个字节一起当作一个字符呢?
UCS-4的解决方案是在0平面(基本平面)同设置一个代理区(Surrogate,U+D800 ~ U+DFFF),这些码点不对应任何字符。因此,这个空段可以用来映射辅助平面的字符。
辅助平面的字符位共有 2^20 个,因此表示这些字符至少需要 20 个二进制位。UTF-16 将这 20 个二进制位分成两半,前 10 位映射在 U+D800 到 U+DBFF,称为高位(H),后 10 位映射在 U+DC00 到 U+DFFF,称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。
D800 二进制:1101101100000000
DC00 二进制:1101110000000000
DFFF 二进制:1101111111111111
utf-16 四字节存储编码方案:
110110yy yyyyyyyy 110111xx xxxxxxxx
(上面的字符y、x就是UCS-4的编码表示)
因此,当我们遇到两个字节,发现它的码点在 U+D800 到 U+DBFF 之间,就可以断定,紧跟在后面的两个字节的码点,应该在 U+DC00 到 U+DFFF 之间,这四个字节必须放在一起解读。
接下来,以汉字(上面一个土字,下面一个口字,其码点为 0x20BB7)为例,说明 UTF-16 编码方式是如何工作的。
0x20BB7显然超出了基本平面的范围(0x0000 - 0xFFFF),因此需要使用四个字节表示。首先用 0x20BB7 - 0x10000 计算出超出的部分,然后将其用 20 个二进制位表示(不足前面补 0 ),结果为0001000010 1110110111。接着,将前 10 位映射到 U+D800 到 U+DBFF 之间,后 10 位映射到 U+DC00 到 U+DFFF 即可。U+D800 对应的二进制数为 1101100000000000,直接填充后面的 10 个二进制位即可,得到 1101100001000010,转成 16 进制数则为 0xD842。同理可得,低位为 0xDFB7。因此得出汉字"?"的 UTF-16 编码为 0xD842 0xDFB7。
Unicode3.0 中给出了辅助平面字符的转换公式:
H = Math.floor((c-0x10000) / 0x400)+0xD800 L = (c - 0x10000) % 0x400 + 0xDC00
根据编码公式,可以很方便的计算出字符的 UTF-16 编码。
经典的不定长编码算法如哈夫曼编码就可以根据对象的出现频率来确定其编码长度,频率高的使用较短的编码,且不存在歧义。
7 详细了解UCS-4的17个平面
直接看表格:
平面
编码范围
中文名称
英文名称
0号平面
U+0000 - U+FFFF
基本多文种平面
Basic Multilingual Plane,简称BMP
1号平面
U+10000 - U+1FFFF
多文种补充平面
Supplementary Multilingual Plane,简称SMP
2号平面
U+20000 - U+2FFFF
表意文字补充平面
Supplementary Ideographic Plane,简称SIP
3号平面
U+30000 - U+3FFFF
表意文字第三平面
Tertiary Ideographic Plane,简称TIP
4~13号平面
U+40000 - U+DFFFF
(尚未使用)
14号平面
U+E0000 - U+EFFFF
特别用途补充平面
Supplementary Special-purpose Plane,简称SSP
15号平面
U+F0000 - U+FFFFF
保留作为私人使用区(A区)
Private Use Area-A,简称PUA-A
16号平面
U+100000 - U+10FFFF
保留作为私人使用区(B区)
Private Use Area-B,简称PUA-B
图示:
UCS-4的0平面对应UCS-2的全部字符编码。
绿色表示专用区PUA(Private Use Area),保留给大家放自定义字符的区域。
平面0: 0xE000-0xF8FF,有6400个码位 平面16:0xF0000 -0xFFFFD 平面17:0x100000-0x10FFFD
红色表示作代理区(Surrogate):
平面0的0xD800-0xDFFF,共2048个码位 代理区的目的用两个UTF-16字符表示BMP以外的字符(见上一节关于utf-16四位存储的说明)。
再将前三个格子放大,蓝绿色部分是汉字,棕色部分是朝鲜语:
统计:
第2平面的汉字可以在以下页面查看:
https://www.qqxiuzi.cn/zh/unicode-zifu.php?plane=2
可在以下网页查看各个平面的字符:
https://www.qqxiuzi.cn/zh/unicode-zifu.php
unicode官网:
https://www.unicode.org/charts/
8 GB2312和unicode
GB2312编码使用的是区位码寻字方式,1-9区存放中文符号,16-55区存放一级汉字,56-87区存放二级汉字。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节)”,第二个字节称为“低位字节”(也称“位字节”)。
“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上 0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是 72*94=6768。其中有5个空位是D7FA-D7FE。
例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节) 0xA1(第二个字节)储存。区位码=区字节+位字节(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。
unicode对汉字进行了重新编码,这和gb2312编码的方式和顺序完全不同,unicode对汉字编码从0x4E00开始,到0x9FA5为止,所以unicode和gb2312编码的转换,就需要一个转换对照表。
void getUnicode2Asc(){ wchar_t wc; setlocale(LC_ALL,"");//设置为本地区域 fflush(stdin); puts("请输入需要查询UCS-2的汉字:\"); wc = getwchar(); wprintf(L"0x%4X\",wc); union{ struct { unsigned int i:4; unsigned int j:4; unsigned int k:4; unsigned int L:4; unsigned int m:4; unsigned int n:4; }; char hanzi[3]; }hz; fflush(stdin); puts("查询gb2312码,请重新输入一遍上述查询的汉字:"); gets(hz.hanzi); printf("0x%X%X%X%X\",hz.j,hz.i,hz.L,hz.k);}
res:
https://www.toutiao.com/a6812925247289819660
https://blog.csdn.net/hezh1994/article/details/78899683
https://blog.51cto.com/u_15127491/2655330
-End-
最简单的编码就是用流水号,但是流水号通常不方便使用(包括不方便数据处理),没有考虑类别划分(大类、中类、小类)的规律性。
数字化还要考虑存储,存储只能使用有限字长,且需要考虑尽量节省存储位。
描述CPU功能的编码方案有各种指令集。 整数的编码方案有原码、补码; 浮点数的编码方案有IEEE754,包括阶码(移码); 位图可以用位来表示颜色信息,有相应的编码和压缩方案; 音频可以采样声波的振动频率来数字化,两样有相应的编码和压缩方案,视频也是如此。
电子计算机是二进制的,编码使用二进制数字,要编码的对象有多少?就要考虑使用多少个二进制位。例如全球有70多亿人口(假设75亿),如果用二进制位给每人一个编号,需要多少个二进制位?就是2的多少次幂等于75亿,是一个对数的计算。log2(7500000000)≈32.8,用33个二进制位就够了。
这里要说的是字符的编码方案。
1 ASCII
英文字符数量少,用7个二进制就够了,但电脑的数据读写的二进制通常使用2的整数倍,就用了8个位,首位用零填充。美国人就搞了个英文字符的编码方案,称为ASCII。编码了128个字符,这100多个字符大部分都可以直接映射到键盘,可以直接输入。
void printAscii(){ for(int i=1;i<=128;i++) { if(i==10 || i ==13) printf("\"); else printf("%3d %c\",i,i); if(i%8==0) printf("\"); }}
虽然只有100多个字符,但其ASCII编码也是极其有规律性的,考虑到了尽可能方便数据处理。如:
大写字母的'A'的编码是是65,其编码是01000001,也就是十进制的12^6+1,
大写字母的'a'的编码是是97,其编码是01100001,也就是十进制的2^6+2^5+1;
大小写如何转换?差别只有第3位。大写转小写,只需要按位转换这个位就行了。
char toLower(char ch){ return ch | 1<<5;}char toUpper(char ch){ return ch & ~(1<<5);} 2 扩展ASCII
英语用 128 个字符来编码完全是足够的,但是用来表示其他语言,128 个字符是远远不够的。于是,一些欧洲的国家就决定,将 ASCII 码中闲置的最高位利用起来,这样一来就能表示 256 个字符。
3 GB2312和BGK
ASCII 码的问题在于尽管所有人都在 0 - 127 号字符上达成了一致,但对于 128 - 255 号字符上却有很多种不同的解释。与此同时,亚洲语言有更多的字符需要被存储,一个字节已经不够用了。于是,人们开始使用两个字节来存储字符。
等中国人们得到计算机时,已经没有可以利用的字节位来表示汉字,况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民,我们不客气地把那些127号之后的奇异符号们直接取消掉,规定一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。 中国人民看到这样很不错,于是就把这种汉字方案叫做 “GB2312“。GB2312 是对 ASCII 的中文扩展。
void printGB2312(){int i,j,sum=0;for(i=0xA1;i<0xAA;i++){for(j=0xA1;j<0xFF;j++) { printf("%c%c",i,j); sum++; }}for(i=0xB0;i<0xF8;i++){for(j=0xA1;j<0xFF;j++) { printf("%c%c",i,j); sum++; } } printf("\合计:%d\",sum); // 7614}
但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来。于是我们不得不继续把 GB2312 没有用到的码位找出来老实不客气地用上。 后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK包括了GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。 后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK扩成了 GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。 中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 “DBCS“(Double Byte Charecter Set 双字节字符集)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处 理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。那时候凡是受过加持,会编程的计算机僧侣 们都要每天念下面这个咒语数百遍: “一个汉字算两个英文字符!一个汉字算两个英文字符……”
void printGBK(){ int sum = 0; FILE * fp; fp = fopen("d:\\\\GBK.txt","w");int i,j;for(i=0x81;i<0xFF;i++){for(j=0x40;j<0x7F;j++){printf("%c%c",i,j); fprintf(fp,"%c%c",i,j); sum++;}for(j=0x80;j<0xFF;j++){printf("%c%c",i,j); fprintf(fp,"%c%c",i,j); sum++;}printf("\");} printf("\合计:%d\",sum); // 23940 fclose(fp); system("d:\\\\GBK.txt"); }
4 Unicode和UCS-2、UCS-4
因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,连大陆和台湾这样只相隔了150海里,使用着同一种语言的地区,也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字,就必须装上一个”汉字系统”,专门用来处理汉字的显示、输入的问题,如果装错了字符系统,显示就会乱了套!这怎么办?而且世界民族之林中还有那些一时用不上电脑的穷苦人民,他们的文字又怎么办?
一个叫 ISO (国际标谁化组织)的国际组织决定着手解决这个问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号的编码!称为“Universal Multiple-Octet Coded Character Set”,简称 UCS,俗称 “unicode”。
UCS-2 采用 16 位存储空间,两个字节编码每个字符,而 UCS-4 采用 4 个字节(实际上只用了 31 位,最高位必须为 0)编码。UCS-2 有 2^16=65536 个码位,UCS-4 有 2^31=2147483648 个码位。
对于ASCII里的那些“半角”字符,unicode包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。
UCS-4 根据最高位为 0 的最高字节分成 27=128 个组(group)。每个组再根据次高字节分为 256 个平面(plane)。每个平面根据第 3 个字节分为 256 行 (rows),每行包含 256 个单元(cells)。当然同一行的单元只是最后一个字节不同,其余都相同。
ISO 只用到 17 个平面,包含 1 个基本平面(BMP)和 16 个辅助平面,最高码位 U+10FFFF。
0 组的 0 号平面被称作 Basic Multilingual Plane,即基本多文种平面,简写 BMP。可知 BMP 区域内的字符只使用了两个字节,码位从 U+0000 至 U+FFFF。它实际上就是 UCS-2 的全部编码范围,后来因为码位不够用才扩展为 UCS-4。
5 多字节字符的输入、输出
例如汉字,键盘只有100多个按键?如何输入汉字?
现在我们使用的各种中文输入法(搜狗拼音输入法,王码输入法)就是中文输入的编码方案。不要看我们现在有各种方便快捷的输入法,最初可是一个老大难问题。
汉字的输出其实就是点阵图形的输出,也就是所谓的字库。
6 多字节字符的存储和读取几个字节做为一个字节编码的问题
Unicode和UCS-2、UCS-4的编码方案,就同时考虑了存储的问题。即要方便存储空间的节约(排在前面的编码可以使用较少的位来存储,排在后面的编码需要使用较多的位来存储)。
UTF-8、UTF-16、UTF-32就是UCS-4存储方案的实现。
unicode在很长一段时间内无法推广,直到互联网的出现,为解决unicode如何在网络上传输的问题,于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。UTF-8就是在互联网上使用最广的一种unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。
与此同时,文件通过文件头(无数据))来标识字符的编码的类型:
Windows使用代码页(code page)来适应各个国家和地区。code page可以被理解为内码。GBK对应的code page是CP936。可以CMD窗口中使用chcp命令来查看,或右击查看属性。 使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。 在bat中使用重定向来生成文本文件时,第一行可以声明chcp 65001,文件对应的存储方案就是utf-8。
对于文件内的字符,按文件头标识的编码方案来解释,对于定长的ASCII和UTF-32,可以使用定长的字节数来表示一个字符。
对于不定长的UTF-8,其每个字节的前几位都特意做了固定编码,用来识别一个字符需要读取几个字节。
UTF-16 的编码长度要么是 2 个字节(U+0000 到 U+FFFF),要么是 4 个字节(U+010000 到 U+10FFFF)。那么问题来了,当我们遇到两个字节时,到底是把这两个字节当作一个字符还是与后面的两个字节一起当作一个字符呢?
UCS-4的解决方案是在0平面(基本平面)同设置一个代理区(Surrogate,U+D800 ~ U+DFFF),这些码点不对应任何字符。因此,这个空段可以用来映射辅助平面的字符。
辅助平面的字符位共有 2^20 个,因此表示这些字符至少需要 20 个二进制位。UTF-16 将这 20 个二进制位分成两半,前 10 位映射在 U+D800 到 U+DBFF,称为高位(H),后 10 位映射在 U+DC00 到 U+DFFF,称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。
D800 二进制:1101101100000000
DC00 二进制:1101110000000000
DFFF 二进制:1101111111111111
utf-16 四字节存储编码方案:
110110yy yyyyyyyy 110111xx xxxxxxxx
(上面的字符y、x就是UCS-4的编码表示)
因此,当我们遇到两个字节,发现它的码点在 U+D800 到 U+DBFF 之间,就可以断定,紧跟在后面的两个字节的码点,应该在 U+DC00 到 U+DFFF 之间,这四个字节必须放在一起解读。
接下来,以汉字(上面一个土字,下面一个口字,其码点为 0x20BB7)为例,说明 UTF-16 编码方式是如何工作的。
0x20BB7显然超出了基本平面的范围(0x0000 - 0xFFFF),因此需要使用四个字节表示。首先用 0x20BB7 - 0x10000 计算出超出的部分,然后将其用 20 个二进制位表示(不足前面补 0 ),结果为0001000010 1110110111。接着,将前 10 位映射到 U+D800 到 U+DBFF 之间,后 10 位映射到 U+DC00 到 U+DFFF 即可。U+D800 对应的二进制数为 1101100000000000,直接填充后面的 10 个二进制位即可,得到 1101100001000010,转成 16 进制数则为 0xD842。同理可得,低位为 0xDFB7。因此得出汉字"?"的 UTF-16 编码为 0xD842 0xDFB7。
Unicode3.0 中给出了辅助平面字符的转换公式:
H = Math.floor((c-0x10000) / 0x400)+0xD800 L = (c - 0x10000) % 0x400 + 0xDC00
根据编码公式,可以很方便的计算出字符的 UTF-16 编码。
经典的不定长编码算法如哈夫曼编码就可以根据对象的出现频率来确定其编码长度,频率高的使用较短的编码,且不存在歧义。
7 详细了解UCS-4的17个平面
直接看表格:
平面
编码范围
中文名称
英文名称
0号平面
U+0000 - U+FFFF
基本多文种平面
Basic Multilingual Plane,简称BMP
1号平面
U+10000 - U+1FFFF
多文种补充平面
Supplementary Multilingual Plane,简称SMP
2号平面
U+20000 - U+2FFFF
表意文字补充平面
Supplementary Ideographic Plane,简称SIP
3号平面
U+30000 - U+3FFFF
表意文字第三平面
Tertiary Ideographic Plane,简称TIP
4~13号平面
U+40000 - U+DFFFF
(尚未使用)
14号平面
U+E0000 - U+EFFFF
特别用途补充平面
Supplementary Special-purpose Plane,简称SSP
15号平面
U+F0000 - U+FFFFF
保留作为私人使用区(A区)
Private Use Area-A,简称PUA-A
16号平面
U+100000 - U+10FFFF
保留作为私人使用区(B区)
Private Use Area-B,简称PUA-B
图示:
UCS-4的0平面对应UCS-2的全部字符编码。
绿色表示专用区PUA(Private Use Area),保留给大家放自定义字符的区域。
平面0: 0xE000-0xF8FF,有6400个码位 平面16:0xF0000 -0xFFFFD 平面17:0x100000-0x10FFFD
红色表示作代理区(Surrogate):
平面0的0xD800-0xDFFF,共2048个码位 代理区的目的用两个UTF-16字符表示BMP以外的字符(见上一节关于utf-16四位存储的说明)。
再将前三个格子放大,蓝绿色部分是汉字,棕色部分是朝鲜语:
统计:
第2平面的汉字可以在以下页面查看:
https://www.qqxiuzi.cn/zh/unicode-zifu.php?plane=2
可在以下网页查看各个平面的字符:
https://www.qqxiuzi.cn/zh/unicode-zifu.php
unicode官网:
https://www.unicode.org/charts/
8 GB2312和unicode
GB2312编码使用的是区位码寻字方式,1-9区存放中文符号,16-55区存放一级汉字,56-87区存放二级汉字。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节)”,第二个字节称为“低位字节”(也称“位字节”)。
“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上 0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是 72*94=6768。其中有5个空位是D7FA-D7FE。
例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节) 0xA1(第二个字节)储存。区位码=区字节+位字节(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。
unicode对汉字进行了重新编码,这和gb2312编码的方式和顺序完全不同,unicode对汉字编码从0x4E00开始,到0x9FA5为止,所以unicode和gb2312编码的转换,就需要一个转换对照表。
void getUnicode2Asc(){ wchar_t wc; setlocale(LC_ALL,"");//设置为本地区域 fflush(stdin); puts("请输入需要查询UCS-2的汉字:\"); wc = getwchar(); wprintf(L"0x%4X\",wc); union{ struct { unsigned int i:4; unsigned int j:4; unsigned int k:4; unsigned int L:4; unsigned int m:4; unsigned int n:4; }; char hanzi[3]; }hz; fflush(stdin); puts("查询gb2312码,请重新输入一遍上述查询的汉字:"); gets(hz.hanzi); printf("0x%X%X%X%X\",hz.j,hz.i,hz.L,hz.k);}
res:
https://www.toutiao.com/a6812925247289819660
https://blog.csdn.net/hezh1994/article/details/78899683
https://blog.51cto.com/u_15127491/2655330
-End-
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询