UTF与UNICODE,ANSI与ASCII、GB2312字符编码与项目属性中”多字节字符集“

之前通过反复设置LANG变量为"en_US.UTF-8"和"zh_CN.UTF-8"来切换中英文man手册时手误将"zh_CN.UTF-8"写成了"zh-CN.UTF-8",系统应该是解析该字符编码名失败后静默采用了"en_US.UTF-8"导致bash显示中文字符为数字编码:

设置回正确的LANG变量后会正常显示中文字符:

百度之后才发现这是UTF-8的八进制编码,索性就搞清楚点编码格式。

以下转自汉字编码及LINUX中文处理--转(括号里是本人拙见)

 英文字符使用256个ASCII字符(32个不可打印与96个不可打印字符+128个扩展的符号)即一个byte表示即可,前128个符号只占用后面7位,最前面的1位为0;后128个符号最前面的1位为1,;

汉字用一个byte表示明显不够(汉字字符数太庞大了),因此最早的汉字编码是采用两个byte来表示。同时为了与原来ASCII英文字符不混淆(2字节字符肯定会"包含到"1字节字符),特别规定:

两个大于127的字节(第1位为1)连在一起时,就表示一个汉字,前面的一个字节(称为高字节)从0xA1(十进制161)到0xF7(十进制247),后面一个字节(低字节)从0xA1到0xFE(十进制254),这样就能组合出(247-161+1)×(254-161+1)=8178个组合,大约7000多个简体汉字+(数学符号+罗马字母+希腊字母+日文假名等),连带ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码(这些字符自然比ASCII字符编码多占一个字节,好与简体汉字对齐统一被编码),这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。这个方案称为GB2312编码,一般称为国标码。

在计算机于中国开始普及年代,如DOS/WIN3.1/Win95等阶段。GB2312立下了汗马功劳。在同一时期,以繁体字为主的台湾也搞了一套类似的编码,称为BIG5编码(繁体中文大五码),原理是一样的,但是与GB2312码不相互兼容(需转换)。

BIG5编码参考繁体中文大五码(Big5)编码详解

https://cloud.tencent.com/developer/article/1382978
这样 BIG5编码的首字节(第一位)与次字节(第二位)组合后对应文字区域

 

BIG5编码每个字也占据2bytes,第一个字节在0xA4-0xC6之间的基本都是常用字区,繁体中文最常用的5401个字的编码值域在此范围内。第一位在0xC9-0xF9之间的区域为次常用字区,繁体中文不常用的7652个字存储在此范围内。此外还有一些造字区、保留区,造字区的本意是官方并不规定此值域内的具体文字,留给后续应用程序或操作系统自己定义。保留区的本意是此区域保留,不做编码使用。然而后来随着BIG5编码的不断完善,BIG5-2003版本发布后,正式将很多定义在保留区和造字区的常用字列入了官方标准当中。例如0xA3E1在上图中显然是属于保留区,但在后来该值在BIG5-2003中被定义为欧元货币符号"€"。

比如第一个字节如果是0x00-0x7F,则表示的是BIG5与ASCII重合部分(此时第二个字节忽略,这与GB2312两个字节都大于127{第1位为1}不同)。第一个字节在0xA1-0xA3的区域为BIG5编码的标点符号和特殊符号区域。比如句号是'0xA143",冒号是"0xA147",问号是'0xA148",希腊字母θ是'0xA363",它们的第一个字节都位于0xA1-0xA3。

GB2312也有很多缺点,一是字符集太小,只能表示几千个常用汉字。大量汉字没法表示,而是与其他汉字表示集不兼容,经常出现乱码的情况。(不兼容或者不冲突的意思是存在相同的两字节的值分别在GB2312与BIG5中对应着不同的内容,所以除非出现一种编码能同时将GB2312与BIG5一一映射到其自己的编码中并保证不冲突,这样这个编码就能同时存储这两种编码的内容而不引起歧义了,对其他语言的文字亦是如此。乱码就是A码将B码的内容按照A码的规则去翻译,自然就乱来了)

UNICODE表示

为了解决全世界文字冲突问题,国际标准组织ISO把所有语言的字符,全部统一编码(就是所有字符的值都不同,自然不会冲突),称为"Universal Multiple-Octel Coded Character Set",简称UCS,或简称Unicode方案。

Unicode规定所有字符包括英文字符由两个字节表示,但为了兼容,原来的ASCII码采用高位字节全部取0低位字节保持为原来ASCII值的方式。

需要注意的是,Unicode只是一个一个符号集,它只规定了符号的二进制表示,却没有规定这个二进制代码应该如何存储(大小端序)。我们一般称为Unicode表示(而不是Unicode编码),是指用两个byte,即一个short来表示的方法,2个字节在32位CPU上正好是一个short型,这样在不同字节序的CPU下,同一个编码有两种排序,有小端序(低位字节在前)和大端序(高位字节在前),两种方案分别称为Unicode、Unicode-Big。

显然Unicode表示不与GB2312或Big5兼容,仍有冲突。

Unicode在制定时没有考虑与任何一种现有的编码方案保持兼容,这使得GBK与Unicode在汉字的内码编排上完全是不一样的,没有一种简单的算术方法可以把文本内容从Unicode表示和另一种编码进行转换,这种转换必须通过查表来进行。

UTF-8

随着互联网兴起,如何在网络上传输unicode字符也是一个问题,于是面向传输的众多UTF(UCS Transfer Format)标准出现了,顾名思义,UTF8就是每次8个位传输数据,而 UTF16就是每次16个位。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母(包含在内码32-126的可打印字符中,第一位同样为0),UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围         | UTF-8编码方式
(十六进制)                       | (二进制)
----------------------------|---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

结合:你真的懂 Unicode 和 UTF-8 是什么关系吗?来看看这个就彻底懂了!

上表可以这样看:由于UTF-8是变字节的编码,一、二、三、四个字节在固定了规则限定的若干位后,按从右到左的顺序存储Unicode字符的二进制位;

UTF-8的有效位按其能表示的对象个数(二进制位的排列组合数),分配一定数目(小于等于对象个数)的Unicode字符,例如二字节的UTF-8编码"110xxxxx 10xxxxxx"能有2^11中组合方式,也就能最多标定2^11=2048个Unicode字符,对应Unicode表示的字符为0x0080-0x07FF,但Unicode表示不是连续的,中间有空当,所以该区间的字符数肯定不等于3777-128+1个,一定是小等于2048个。

现在可以手撕一下最开始遇到的中文字符"年"被UTF-8书写成'$'\345\271\264的出处了:

首先百度中文字符"年"的Unicode表示为'\u5e74',这是一个16进制表示,对应的二进制表示是"0101 1110 0111 0100",将该二进制按从右到左顺序填充到UTF-8规划好的三字节的有效位中,把所有16位二进制位一一填充到三字节空出来的4+6+6共16个二进制位:

11100101 10111001 10110100

再把这三个字节分别用八进制表示成345、271、264,这就是linux表示中文"年"的规则。

GBK

    GBK编码(Chinese Internal Code Specification)是中国大陆制订的、等同于UCS的新的中文编码扩展国家标准。GBK编码能够用来同时表示繁体字和简体字,而gb2312只能表示简体字,GBK是兼容gb2312编码的。GBK工作小组于1995年10月,同年12月完成GBK规范。该编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。Windows95/98简体中文版的字库表层编码就采用的是GBK,通过GBK与UCS之间一一对应的码表与底层字库联系。

  (中国大陆)一般有时把ASCII与GB2312混排称为ANSI,它与UTF-8,UNICODE,UNICODE BIG称为四种编码。

ANSI

使用0x00-0x7F(0-127)范围的1个字节表示1个英文字符,超出此范围的使用0x80-0xFFFF来编码,比如简体汉字"中"在简体中文操作系统中(如上VS2010项目属性选择"多字节字符集")使用[0xD6,0xD0]这两个字节存储。

20200526,当项目属性分别使用"多字节字符集"、"Unicode字符集"时,_T()宏将字符串字面值按"ANSI(GB2312)码"、"Unicode码"进行编码,L宏始终将字符串字面值按Unicode码进行编码,不加任何宏的字符串"xxxxx"始终按ANSI(GB2312)码对单字节字符或宽字符进行编码;

在调试监视变量时VS2010将对char值以"ASCii码"解释(就是光标移动到变量时的解释值),对wchar_t值以"Unicode码"解释。此时,当宽字符被转成char后(比如ATL/MFC的CStringW转char[])进行解释会因匹配不到ASCii码而在编译器中显示'?'。赋给char[]或TCHAR[](项目使用多字节字符集时)的宽字符的字面值将按ANSI(GB2312)码存储,即将宽字符的两个字节当做两个"单字节ASCii字符"存储,但翻译时尝试按ASCii码进行解释,找不到时编译器会显示'?',ASCii字符仍按ASCii码存储;项目使用Unicode字符集时,赋给wchar_t[]或TCHAR[](项目使用Unicode字符集时)的宽字符的字面值将按Unicode码存储,翻译时自然按Unicode码进行翻译,编译器自然能正确显示;

不同的国家和地区制定了不同的标准,由此产生了GB2312、GBK、GB18030、Big5、Shift_JIS等各自的编码标准。这些使用多个字节来表示一个汉字字符的各种汉字延伸编码方式,称为ANSI编码。在简体中文Windows操作系统中,ANSI编码代表GBK编码;在繁体中文Windows操作系统中,ANSI编码代表Big5;在日文Windows操作系统中,ANSI编码代表Shift_JIS编码(日文保留有不少汉字)。

简单的说,在简体中文系统下,ANSI编码代表GB2312编码(ASCII+GBK的简体中文部分也即GB2312);在日文操作系统下,ANSI编码代表JS编码。

不同ANSI编码之间互不兼容,ANSI编码表示英文字符时用一个字节,表示中文用两个或四个字节。

ANSI编码作为中国以及部分亚太地区的多字符编码格式,Windows 系统和OS X都是提供原声支持的。但即便如此,许多国外开发者仍然在开发笔记或文字录入类应用时将ANSI编码完全忽略,只加入全球通用的UTF-8编码。

文本文件类型

   因为并存好几种编码,软件处理文本文件是如何判断类型的?实际如果不加一些附加信息,软件也难判断文本是哪一种格式.一般是文件前面加入字节序标记BOM(Byte Order Mark)码。其中有下表:

字节序编码格式
00 00 FE FFUTF-32,big-endian
FF FE 00 00UTF-32,little-endian
FE FFUTF-16,big-endian/即一般的UNICODE-BIG
FF FEUTF-16,little-endian/即UNICOdE
EF BB BFUTF-8

这样只要打开文本文件内容,查看前四个字节表示的字节序,就能判断出是哪一种格式。如果全都不是,意味着是ANSI编码(单字节ASCII码+双字节GB2312码,前者应该是0-127的ASCII字节码,首位为0。后者是两个大于127的GB2312字节码,首位均为1。)

一些编码格式一般是约定成俗的,如*.lrc,往往使用ASCII与GB码混排,即ANIS格式。C源程序采用ASCII。但中间的汉字在不同系统下有不同规定LINUX采用UTF-8,WINDOWS采用GB码。

Windows/Unix 文本回车符.

   处理文本文件还有一个细节,是WINDOWS下敲入回车会输入回车符\r+换行符\n两个字符即"\r\n",而UNIX敲回车只输入回车符"\n",而它还有一个特殊规定,最后一行是空行,即文件结尾以两个换行符"\n\n"结尾。大部分软件能识别两种格式,但是WINDOWS记事本打开LINUX文本文件时,并不换行而是显示黑框。

   但fgets之类实现是最早在UNIX实现,所有读出来最后的字符都是\n,WINDOWS上也是如此,必须用fopen(name,"rb")然后用fread才能读出\r\n来。

标准C宽字节类型

  strlen(),计算结果只针对ASCII单字节字符的串有效,对于2个byte字节的符号无法处理。因此标准C中,制定了wchar_t,它一般被定义成unsigned short 型。对宽字节的函数要采用新的w打头的接口:

如求宽字符字符串的长度的函数是

#include <wchar.h>

size_t wcslen(const wchar_t *s);

Linux 下汉字处理

   Linux 下的汉字编码是以UTF-8,这从RHEL的中文版的语言就可以知道,中文环境下,环境变量LANG的值为 zh_CN.UTF8,而WINDOWS自WINDOWS NT开始,内部都采用UNICODE表示。因此两者在编程有着细微差别。

如果是带汉字的文本可参考相应的BOM来处理。但是在显示、打印时要因应不同的系统采用不同格式。

 如LINUX下控制台下,需要UTF-8格式才能正确处理。象SDL的图形界面下,汉字要转成UNICODE或UTF-8才能正常显示。文本文件还好处理,但如果在C代码里出现汉字常量,如printf("黄新宇\n");这个有不同的情况。如果这个C代码是在LINUX编辑,则C源程序中是UTF-8直接可以显示,如果这个C代码是在WINDOWS编辑拷贝过来。则很有可能是GB码,这样程序编译后在LINUX控制台上乱码。

另外LINUX中文文件名也是UTF-8编码的,可以在fopen中直接采用中文编码。如果WINDWOS的中文则有可能是UNICODE编码,但在samba拷贝后会自动转换。

 原文地址 http://blog.chinaunix.net/u3/105675/showart_2121442.html

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VR(Virtual Reality)即虚拟现实,是一种可以创建和体验虚拟世界的计算机技术。它利用计算机生成一种模拟环境,是一种多源信息融合的、交互式的三维动态视景和实体行为的系统仿真,使用户沉浸到该环境。VR技术通过模拟人的视觉、听觉、触觉等感觉器官功能,使人能够沉浸在计算机生成的虚拟境界,并能够通过语言、手势等自然的方式与之进行实时交互,创建了一种适人化的多维信息空间。 VR技术具有以下主要特点: 沉浸感:用户感到作为主角存在于模拟环境的真实程度。理想的模拟环境应该使用户难以分辨真假,使用户全身心地投入到计算机创建的三维虚拟环境,该环境的一切看上去是真的,听上去是真的,动起来是真的,甚至闻起来、尝起来等一切感觉都是真的,如同在现实世界的感觉一样。 交互性:用户对模拟环境内物体的可操作程度和从环境得到反馈的自然程度(包括实时性)。例如,用户可以用手去直接抓取模拟环境虚拟的物体,这时手有握着东西的感觉,并可以感觉物体的重量,视野被抓的物体也能立刻随着手的移动而移动。 构想性:也称想象性,指用户沉浸在多维信息空间,依靠自己的感知和认知能力获取知识,发挥主观能动性,寻求解答,形成新的概念。此概念不仅是指观念上或语言上的创意,而且可以是指对某些客观存在事物的创造性设想和安排。 VR技术可以应用于各个领域,如游戏、娱乐、教育、医疗、军事、房地产、工业仿真等。随着VR技术的不断发展,它正在改变人们的生活和工作方式,为人们带来全新的体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值