说起字符编码首先可能想到的词汇有Unicode,UTF,UCS,内码,区位码,跨平台等词汇,甚至还有输入法,乱码,emoji,微软雅黑,URL encode等相关的词汇也会冒出来,足以说明字符编码在计算机中重要的地位。程序员关心的是在自己的代码中如何处理好字符编码的问题,特别是像C/C++这样历史悠久而又偏向底层的语言中如何处理好这一问题。实际上这个问题在今天已经得到了很好的解决,前辈们通过努力使得今天的字符编码基本上不再困扰程序的使用者和编程人员,但其留下的诸多历史痕迹却还一直在困扰着一代又一代的编程初学者。本系列博客共有五篇,尽量详细但不失广度,通俗不失深度地介绍关于字符编码的内容,但求抛砖引玉。

  详谈字符编码[一]将介绍编码,输入码,机内码,字形码,字形库等概念,主要说一下这些概念给我们挖的坑。

  接下来的几篇还会介绍“什么是代码页”,“字符输出与消除乱码”,“宽窄字符--字符相关的数据结构”,“常用IO函数的效率分析”等。

一.编码

  编码(encode)的概念并不仅仅出现在计算机科学中,字符编码(character encoding)就是要找到一种能够用表示字符的方案,以方便存储与传输。

  电影《无间道》中梁朝伟和黄秋生通过传输莫斯电码的方式传输信息,再或者小说里两情相悦的男女自己发明一套符号交流感情的桥段,这都是一种编码。但我们要谈的主要还是大家公认的字符的数字编码。这些编码像GBK,UTF-8,UCS-2,ASCII等等。还有Unicode?这就要说说这几个概念的不同了。

  ASCII:信息技术萌发在西方社会,最早的编码也只针对英语的习惯(ASCII只定义了英语字母和数字,符号等)。那时候总共也不超过128个字符,编码方式一张表就全说明白了,表的内容正是字符与数字(0到127)的一一对应。在计算机上的具体实现方式就是用数字对应的二进制无符号数作为字符的机器表示

  因为那时候要编码的字符太少,人们甚至都没怎么感觉到“规定字符和数字的对应方式”“规定数字的二进制表示方式”是两个相对独立的过程。多年后,面对着浩如烟海的待编码字符,这种分治成为必要。

  Unicode:Unicode一开始定位的问题就是给全世界的所有字符(包括古代字符)一个统一的身份证号。所谓统一就是谁跟谁也不会冲突,每个字符都有自己的位子。相比给128个字符编码,这个问题的复杂程度前无古人。分离“制定字符集”和“制定二进制编码”这两个过程势在必行。

  制定统一字符集就是给全世界的字符一个编号,称为码点(code point ),一般用这样“U+7231”(表示汉字 爱 )的方式表示。码点是给人看的,机器只认识二进制,不认识什么叫”U+7241“。所以字符集定义完成也只完成了一半工作,但已经完成了主要的工作。另一部分的工作就是把数字定义为二进制编码,这时出现了多种方案,著名的就有UTF-8,UTF-16,UTF-32,UCS-2,UCS-4。

  字符集说明这种表示方式支持多少字符,比如Unicode能表示很多字符(而且仍在不断扩充),ASCII就只有128个。而编码方式则用来说明怎么用二进制表示字符集里字符对应的数字。到这里应该明白,Unicode是指一个字符集,而UTF-8,UCS-2都是具体的编码方式。ASCII呢,我想应该理解为它既说明了字符集又说明了编码方式。

  分开”定义字符集“和”定义编码“这两部分的工作,好处有很多,我大概想到三点:

  1.这两部分工作用到的领域知识并不相同,因此天然需要分开。定义字符集的专家需要相当的社会学,语言学的人文知识,而编码工作需要由有计算机底层知识的工程师去完成。

  2.定义字符集的工作可以不受编码工作的影响,有利于字符集今后的扩充。Unicode的扩充一直在进行,但编码方式基本只有UTF-8和UTF-16使用的最多,今后也基本不会再变。

  3.不同的系统可以选择不同的二进制实现,哪个方便选哪个。不同的用途也可以选择不同的编码,比如网络传输用UTF-8,内部存储用UTF-16。

二.UTF-8,UTF-16,UTF-32,UCS-2,UCS-4

  网上已经有不少介绍具体编码方式的文章,这里不再赘述,只画一下重点。

  Ⅰ。UTF-16与UCS-2是不同的编码方式(UCS-4也不同与UTF-32)。简单的来说,UCS是较旧的概念。早期Unicode认为32bit足以表示全世界的字符,但现实是后来发现不够便经过了一次扩充(U+XXXX变成U+XXXXXX,比如U+1F60A是emoji中的笑脸)。UCS-2只能表示扩充前的字符(请自行百度”Basic Multilingual Plane“)。UTF-16完全兼容UCS-2,但支持所有Unicode字符,代价就是UTF-16是变长的,一个UTF-16字符可能是16bit也可能用32bit(请自行百度”surrogate pair“)。

  Ⅱ。UTF-16,UTF-32存在大小端的问题,UTF-8不存在。简单来说因为UTF-16的码元的2字节,UTF-32的码元的4字节都是多字节,而UTF-8的码元是一个字节,单字节不存在大小端问题(无所谓字节序)。

    但真正要解释清除还要说一下什么是Unicode的码元,码元(是Unicode的码元,不是通讯学里说的那个码元)是机器一次处理的数据单位,是字节(8bit)的整数倍。要知道机器可不是一个字符一个字符处理的,而是一个码元一个码元的处理,具体来说C++中UTF-8不是用char数组存储吗,所以机器一次处理一个char类型(8bit)。如果码元只包含一个字节,一次处理一个字节当然不会有大小端的问题。但如果是多字节码元(UTF-16,UTF-32)就有区别了,x86是小端模式(x64不过是x86_64),他表示的UTF-16的’爱‘当然也应该等于7231但是在内存中就是按照0x3172这样存储的,不过,也没关系毕竟机器自己认得在wchar_t的上下文中0x3172表示的值就是0x7231。问题是一旦换一台新机器,鬼知道你的0x3172表示的是3172还是7231?新机器也是小端那还好,默认认为0x3172就是7231。但如果是大端的机器,默认理解3172就是3172,爱就变成另一个字了。再看单字节码元的UTF-8,不论在大端还是小端的机器中都存储为E788B1,而且都理解为E788B1,因此也就不存在大小端问题了。

  Ⅲ。BOM(Byte Order Mark)是为了区分大小端而存在的。用U+FEFF作为第一个字符(选择它是因为U+EFFF在是非法的码点),U+FEFF这个码点的名称就是”零长不折行空格“,意思就是什么都不显示,零长度嘛,所以即便在字符中任意插入U+FEFF也不会影响显示出来的结果。一台机器读取字符时发现前两个字节是FFEF,就知道之后的文本是大端表示,如果前两个字节是EFFF,就知道之后的文本是小端表示。UTF-8没有大小端问题,BOM也就可有可无,但如果有的话应该是什么呢?就是U+FEFF采用UTF-8编码得到的:EFBBBF。

  Ⅳ。知乎上有这样的问题:”Windows为什么用GBK而不是UTF-8?“,“为什么Windows简体中文默认编码是GBK?”这可真冤枉微软了,Windows会放着Unicode这么好的东西不用吗?其实Windows2000之后的操作系统内码都是UTF-16了。如果你还有有这样的误会,请关注后续博客"什么是代码页"。

三.机内码,输入码,字形码

  这三个概念是应该放在一起的,因为分别代表了一个字符从输入到处理存储再到输出计算机的过程。输入阶段用到的是输入码,比如拼音码,五笔字型码,区位码,他们基本上都对应了一类输入法,用来完成字符的输入。当我们使用了五笔输入并在按键上按下EP这两个按键时,一系列按键消息传到输入法程序中,输入法在把这一系列按键消息翻译成我们想输入的汉字:爱。机内码则是字符在计算机内的表示方式,一般说的字符编码也是指机内码。字形码就有意思了。计算机知道内存中的一个字符是“爱”,要把它显示到屏幕或打印到纸上,这就需要字形码。他包含了一个字符形状的点阵信息或者矢量信息,总之是和“字符的样子”有关的信息。

                  

                     图1.1 汉字“爱”的16*16点阵

  字形的信息存储在字库中(win10中C:/windows/Fonts/目录下的就是关于字形的文件了)。比如上边的“爱”字是一个可以查询字形信息的程序输出的,这个程序就需要读取附带的字库信息。单片机想要在一个LED显示屏上显示一个字符时用到的底层驱动程序也是类似原理,针式打印机要在纸上打印同样需要字形信息。一个字当然可以有很多种字体,每一种字体都需要对应字形库的支持。多说一句字形设计可是有著作权保护的,方正楷体可以免费商用,但微软雅黑商用就需要付费了(但Windows用户可以在屏幕上显示微软雅黑,因为这部分版权费微软已经给方正付过了)。

  任何刚学完控制台输出的新手都有写一个字符画程序的冲动,这里有一个以前写的可以将图片转换为bmp位图字符画的程序例子,涉及字库的使用,bmp位图的文件格式,生成灰度图等知识。(自己吐槽:这个程序很鸡肋,要么看得清图片全貌看不清每个汉字,要么看得清汉字但图片却超出了屏幕范围,要想写一个更好的字符画程序不得不研究一下图像处理呢)这里抖胆把效果展示一下。

      

    原图        缩小后的字符画               字符画局部,可以看到由汉字组成

这篇的全部内容就是这样了,下一篇会介绍”宽窄字符--字符相关的数据结构“,包括C++11中新加入的char16_t和char32_t的内容。喜欢就推荐一下吧。

祝大家国庆,中秋快乐!

转载于:https://www.cnblogs.com/painterQ/p/7582768.html

详谈字符编码[一]字符编码中的坑相关推荐

  1. java中字符与字节的编码关系

    为什么80%的码农都做不了架构师?>>>    一个英文字母字符存储需要1个字节.在 GB 2312 编码或 GBK 编码中,一个汉字字符存储需要2个字节. 在UTF-8编码中,一个 ...

  2. 【Java基础】Java中的char是否可以存储一个中文字符之理解字符字节以及编码集

    Java中的一个char采用的是Unicode编码集,占用两个字节,而一个中文字符也是两个字节,因此Java中的char是可以表示一个中文字符的. 但是在C/C++中由于采用的字符编码集是ASCII, ...

  3. php %3cphp用大括号表示,整理HTML5中支持的URL编码与字符编码_html5教程技巧

    URL 编码URL 编码就是将 URLs 中不宜打印的字符或者具有特殊意义的字符转换为 Web 浏览器和服务器明白且普遍接受的表示法. 这些字符包括: ASCII 控制字符 - 不宜打印的字符通常用于 ...

  4. python无法打印unicode编码_【整理】Python中实际上已经得到了正确的Unicode或某种编码的字符,但是看起来或打印出来却是乱码...

    [背景] Python中的字符编码,其实的确有点复杂. 再加上,不同的开发环境和工具中,显示的逻辑和效果又不太相同,尤其是,中文的,初级用户,最常遇到的: (1)在Python自带的IDE:IDLE中 ...

  5. unix系统编码 java_JAVA字符编码系列三:Java应用中的编码问题

    这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记录下来以便日后参考. 为了构成一个完整的对文字编码的认识和深入把握,以便处理在Java开发过程中遇到的各种问 ...

  6. python3字节转化字符_浅谈 Python3 中对二进制数据 XOR 编码的正确姿势

    Python3 中的默认编码是 UTF-8,这给大家写 Python 代码带来了很大的便利,不用再像 Python2.x 那样为数据编码操碎了心.但是,由于全面转向 UTF-8 编码,Python3 ...

  7. java 字节编码_java中字符与字节的编码关系

    一个英文字母字符存储需要1个字节.在 GB 2312 编码或 GBK 编码中,一个汉字字符存储需要2个字节. 在UTF-8编码中,一个英文字母字符存储需要1个字节,一个汉字字符储存需要3到4个字节.在 ...

  8. C语言学习(十二)C语言中的字符(宽字符与窄字符)、从字符谈谈C语言的编码、转义字符

    C语言学习(十二)C语言中的字符(宽字符与窄字符).从字符谈谈C语言的编码.转义字符 目录 C语言学习(十二)C语言中的字符(宽字符与窄字符).从字符谈谈C语言的编码.转义字符 英文字符 字符的表示 ...

  9. mysql外码内码定义_刨根究底字符编码之六——简体汉字编码中区位码、国标码、内码、外码、字形码的区别及关系...

    简体汉字编码中区位码.国标码.内码.外码.字形码的区别及关系 GB2312.GBK.GB18030等GB类汉字编码方案的具体实现方式是怎样的?区位码是什么?国标码是什么?内码.外码.字形码又是什么意思 ...

最新文章

  1. 石墨计算机,高性能计算机助力石墨烯生产工艺的优化
  2. 判断输入的字符是不是数字
  3. 技术开发中一些名词解释
  4. hibernate mysql 映射_hibernate与mysql映射类型对应表与mysql导入导出
  5. TensorFlow读取MNIST数据集错误的问题
  6. python99乘法表while翻译_Python学习之while练习--九九乘法表
  7. CentOS7安装mysql8并配置
  8. python docx table 边框_使用pythondocx指定表中的边框外观
  9. bat批处理命令:实现读取文件内容,并调用浏览器打开网址,搜索文件内容
  10. 解决Maven cannot access in offline mode问题
  11. (Java实现) 美元汇率
  12. Shell脚本之IP验证
  13. NMS、Soft-NMS、Softer-NMS
  14. 剑指Offer三天挑战赛03~15
  15. WIN2012远程桌面授权服务器许可证问题解决方法
  16. 计算机能够自动完成运算或处理过程的基础是,计算机文化基础题库.doc
  17. 2022年消费金融行业研究报告
  18. COOKIE ADN SESSION
  19. Python Matplotlib绘制漂亮的K线图,利用Tushare绘制K线图
  20. 解决查看网页源代码html代码样式乱了

热门文章

  1. Windows10的Ubuntu子系统开启桌面环境
  2. Ubuntu下Wine使用教程
  3. java实现邮件发送_基于JavaMail的Java实现简单邮件发送功能
  4. iOS_系统原生分享
  5. 电子或通讯领域当前的主流技术及其社会需求调查报告
  6. 程序员8月薪资统计出炉,最吃香的岗位竟然是······
  7. 夜莺日志采集mtail
  8. 概率论与数理统计笔记系列之第二章:随机变量及其分布
  9. 校园企业车辆维修报修管理系统设计与开发
  10. 「中国加班第一楼」深圳科兴万人大撤离!拖主机带屏幕,程序员公交上写代码!...