精华内容
下载资源
问答
  • 字符编码

    2020-12-17 22:44:48
    字符编码: ​ 按照某种规则,将字符存储到计算机中,称为编码;反之,将存储在计算机中的二...计算机中要准确的存储和识别各种文字的字符符号,需要进行字符编码,一套字符集至少有一个套字符编码 常见的字符编码

    字符编码:

    ​ 按照某种规则,将字符存储到计算机中,称为编码;反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。在进行编码和解码过程中,我们必须采用是同一种规则,才能数据正常,否则,会会导致乱码现象。

    • 字符编码:就是一套自然语言中的字符与二进制数之间的对应规则。

    字符集:

    • 字符集:是一个系统可支持的所有字符的集合,包括各国文字,标点符号,图形符号,数字等,也叫编码表。

      计算机中要准确的存储和识别各种文字的字符符号,需要进行字符编码,一套字符集至少有一个套字符编码

    常见的字符编码集有ASCII字符集、GBK字符集、Unicode字符集。

    ASCII字符集:

    • ASCII是基于拉丁字母的一套编码系统,用于显示现代英语。
    • 基本的ASCII字符集,使用7位(bit)表示一个字符,共128个字符。ASCII的扩展字符集使用8位(bit)表示一个字符,共256个字符。

    ISO-8859-1字符集:

    • 拉丁码表,别名–Lantin-1,用于显示欧洲使用的语言,包括荷兰,丹麦,德语,意大利语,西班牙语等。
    • ISO-8859-1使用单字节编码,兼容ASCII编码。

    GB系列字符集

    • GB2312:称为简体中文码表,里面大概含有7000多个简体汉字,此外数学符号,罗马希腊的字母、日本的假名都编进去了,连在ASCII里的原来就与的数字、标点、字母都统统重新用的两个字节编写进去了。
    • GBK:最常用的中文编码。是在原来GB23121码表基础上进行扩展。使用双字节编码。共收录了21000多个汉字,完全兼容GB2312,标准,同时支持繁体汉字以及日韩汉字等。
    • GB18030:最新的中文码表,共收录了7万多个汉字,采用多字节编码,每个字可以由1个字节,2个字节或者4个字节组成,支持国内少数名族的文字,同时支持繁体字以及日韩汉字等。

    Unicode字符集:

    • Unicode编码系统为表达任意语言的任意字符而设计的,是业界的一种标准,也成为统一编码,标准万国码表。
    • 它最多使用4个字节的数字来表示每个字母、符号、或者文字,有三种常见的编码方案:UTF-8,UTF-16,UTF-32。
    • UTF-8编码表,用来表示Unicode标准中的任意字符,编码规则:
      1. 128个US-ASCII字符,使用的是一个字节编码
      2. 拉丁字的字母,需要两个字节编码
      3. 大部分常见的汉字,使用的是三个字节编码
      4. 其他极少数的辅助字符,采用的四个字节编码。
    编码会引发的问题

    由于编码规则不一致,导致引发乱码现象。

    那么如何读取GBK编码的文件呢?

    展开全文
  • 拨开字符编码的迷雾--字符编码概述

    万次阅读 2017-11-27 20:46:23
    相信不少人在字符编码上面摔过跟头,这篇文章针对开发中需要了解的字符编码知识进行了简要的讲解,希望能够对大家有所帮助。 1. ASCII及其扩展 1.1 什么是ASCII字符集 字符集就是一系列用于显示的字符的...

    为什么这样的字符串{"data":"颸颸"},JSON库(如jsoncpp)会解析失败?
    为什么界面上韩文显示乱码?
    ASCII和ANSI有什么区别?
    相信不少人在字符编码上面摔过跟头,这篇文章针对开发中需要了解的字符编码知识进行了简要的讲解,希望能够对大家有所帮助。

    1. ASCII及其扩展

    1.1 什么是ASCII字符集

    字符集就是一系列用于显示的字符的集合。ASCII字符集由美国国家标准协会(American National Standard Institute)于1968年制定一个字符映射集合。

    ASCII使用7位二进制位来表示一个字符,总共可以表示128个字符(即2^7,二进制000 0000 ~ 111 1111 十进制0~127)。

    ASCII字符集中每个数字对应一个唯一的字符,如下表:
    这里写图片描述

    因为其对应关系非常简单,不需要特殊的编码规则,所以严格来讲ASCII不能算字符编码,因为它没有规定编码规则。我们只是习惯将ASCII字符集称之为ASCII码、ASCII编码。

    1.2 ASCII的扩展

    1.2.1 最高位扩展 - ISO/IEC 8859

    ASCII字符集是美国人发明的,这些字符完全是为其量身定制的。但随着计算机技术的发展和普及,传到了欧洲(如法国、德国)各国。由于欧洲很多国家中使用的字符除了ASCII表中的128个字符之外,还有一些各国特有的字符,于是欧洲人民发现ASCII字符集表达不了他们所要表达的东西呀。怎么办了?他们发现ASCII只使用了一个字节(8位)之中的低7位,于是欧洲各国开始各显神通,打起了那1个最高位(第0位)的主意,将最高位利用了起来,这样又多了128个字符,从而满足了欧洲人民的需要。

    但因为每个国家的需求不一样,各国都设计了不同的方案。为了结束这种混乱的局面,国际标准化组织(ISO)及国际电工委员会(IEC)联合制定了一系列8位字符集的标准,统称为ISO 8859(全称ISO/IEC 8859)。注意,这是一系列字符集的统称。如ISO/IEC 8859-1(也就是常听到的Latin-1)支持西欧语言,ISO/IEC 8859-4(Latin-4)支持北欧语言等。

    完整列表如下(摘自百度百科):
    ISO/IEC 8859-1 (Latin-1) - 西欧语言
    ISO/IEC 8859-2 (Latin-2) - 中欧语言
    ISO/IEC 8859-3 (Latin-3) - 南欧语言,世界语也可用此字符集显示。
    ISO/IEC 8859-4 (Latin-4) - 北欧语言
    ISO/IEC 8859-5 (Cyrillic) - 斯拉夫语言
    ISO/IEC 8859-6 (Arabic) - 阿拉伯语
    ISO/IEC 8859-7 (Greek) - 希腊语
    ISO/IEC 8859-8 (Hebrew) - 希伯来语(视觉顺序)
    ISO 8859-8-I - 希伯来语(逻辑顺序)
    ISO/IEC 8859-9 (Latin-5 或 Turkish) - 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
    ISO/IEC 8859-10 (Latin-6 或 Nordic) - 北日耳曼语支,用来代替Latin-4。
    ISO/IEC 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
    ISO/IEC 8859-13 (Latin-7 或 Baltic Rim) - 波罗的语族
    ISO/IEC 8859-14 (Latin-8 或 Celtic) - 凯尔特语族
    ISO/IEC 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的芬兰语字母和大写法语重音字母,以及欧元符号。
    ISO/IEC 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。

    我们在数据库中常见到的Latin-1、2、5、7其实就是上面提到的针对特定语言的ASCII扩展字符集。
    这里写图片描述

    1.2.2 多字节扩展 - GB系列

    前面讲到了,欧洲各国有效利用闲置的最高位,对ASCII字符集进行了扩展。可是欧洲人民没有想到的是(当然他们也不用想这么多),在大洋彼岸有着一个拥有五千年历史的伟大民族,她拥有着成千上万的汉字,1个字节显然不够表达如此深厚的文化底蕴。

    于是当计算机引入到中国之初,国家技术监督局就设计了GB系列编码方案(GB=guo biao)。
    GB编码方案使用2个字节来表达一个汉字。同时为了兼容ASCII编码,规定各个字节的最高位(首位)必须为1,从而避免了和最高位为0的ASCII字符集的冲突。

    GB系列字符集经历下面的几个发展过程:

    编码名称发布时间字节数汉字范围
    GB23121980年变字节(ASCII 1字节,汉字2个字节)6763个汉字
    GB130001993年第一版变字节(ASCII 1字节,汉字2个字节)20902个汉字
    GBKWindows95中2个字节21886个汉字和图形符号(含GB2312,BIG5中所有字符)
    GB180302000年第一版变字节(ASCII 1字节,汉字2个或4个字节)27484个汉字

    每一次迭代,支持的字符数量都会增加,而且每一次迭代都会保留之前版本支持的编码,所以做到了向上兼容。

    1.2.3 全角与半角

    因为汉字在显示器上的显示宽度要比英文字符的宽度要宽一倍,在一起排版显示时不太美观。所以GB编码不仅仅加入了汉字字符,而且包括了ASCII字符集中本来就有的数字、标点符号、字母等字符。这些被编入GB编码的数字、标点、字母在显示器上的显示宽度比ASCII字符集中的宽度宽一倍,所以前者称为全角字符,后者称为半角字符。

    2. ANSI

    2.1 ANSI与代码页

    前面说到了世界各国针对ASCII的扩展方案(如欧洲的ISO/IEC 8859,中国的GB系列等),这些ASCII扩展编码方案的特点是:他们都兼容ASCII编码,但他们彼此之间是不兼容的。微软将这些编码方案统称为ANSI编码。故ANSI并不是特指某一种编码方案,只有知道了在哪个国家,哪个语言环境下,才知道它具体表示哪个编码方案。

    在windows操作系统上,默认使用ANSI来保存文件。那么操作系统是如何知道ANSI到底应该表示哪种编码了,是GBK,还是ASCII,或者还是EUC-KR了? windows通过一个叫"Code Page"(翻译为中文就叫代码页)的东西来判断系统的默认编码。
    简体中文操作系统默认的代码页是936,它表示ANSI使用的是GBK编码。
    GB18030编码对应的windows代码页为CP54936。

    可以使用命令chcp来查看系统默认的代码页.

    汉字这里写图片描述(念suì,因为CSDN编辑器不支持该汉字,所以用图片代替,吐槽~~~)只包含在GB18030中,GB2312、GB13000、GBK中均不包含。默认情况下,在Visual Studio中输入该汉字,visual studio会使用CP936(即GBK)来保存代码文件,但如果在代码文件中输入该汉字,visual studio弹出如下提示要求用户选择代码页:
    这里写图片描述
    这里写图片描述

    2.2 更改默认代码页

    2.2.1 chcp命令

    可以使用chcp命令来更改默认代码页,如chcp 437将默认代码页更改为437(美国)。

    2.2.2 控制面板

    在“控制面板”–>“区域和语言”–> “更改系统区域设置”中更改系统默认的代码页为“中文(简体,中国)”。

    2.2.3 代码修改

    也可以通过代码更改默认的代码页:

    char *setlocale(
       int category,
       const char *locale 
    );
    

    3. Unicode

    3.1 Unicode产生背景

    各个国家使用不同的编码规则,虽然他们都是兼容ASCII的,但它们相互却是不兼容的。

    试想法国人Jack写了一封名为"love_you.txt"的信,传给了他的德国朋友Rose,Rose想要在windows系统上打开这个文件,她需要知道德国使用的字符编码是Latin-1,然后还要确保她的计算机上安装了该编码,才能顺利的打开这个文件。
    如果上面这些还能忍受,那么随着网络的发展,你从互联网上获取的文件,你很有可能不知道它来自哪个国家,使用的哪种编码。这也就是Email刚诞生时常常出现乱码的原因,发信人和收信人使用的编码可能是不一样的。

    于是The Unicode Standard(统一码标准)横空出世,它由The Unicode Consortium于1991年发布,我们习惯称它为Unicode字符集。

    Unicode字符集和ASCII字符集一样,也只是一个字符集合,标记着字符和数字之间的映射关系,它不包含任何编码规则和方案。和ASCII不一样的是,Unicode字符集支持的字符数量是没有限制的(具体可以参考Unicode规范)。

    我们通常认为的Unicode字符固定占用2个字节的观点是错误的。如这里写图片描述(念suì)Unicode码为D852 DF62

    那么Unicode字符是怎样被编码成内存中的字节的了?它是通过UTF(Unicode Transformation Formats)实现的,比较常见得有UTF-8,UTF-16。

    在windows系统上汉字默认使用CP936(即GBK编码),占2个字节。而大多数Unicode字符的Unicode码值也占2个字节,所以大多数人误以为汉字字符串在内存中的值就是Unicode值,这是错误的。
    可以从 站长工具-Unicode 查询汉字的Unicode码值。

    3.3 字符集与字符编码的区别

    从ASCII、GB2312、GBK、GB18030、Big5(繁体中文)、Latin-1等采用的方案来看,它们都只是定义了单个字符与二进制数据的映射关系,一个字符在一个方案中只会存在一种表示方式,所以我们说GB2312是字符集还是字符编码方式都无所谓了。但是Unicode不一样,Unicode作为一个字符集可以采用多种编码方式,如UTF-8, UTF-16, UTF-32等。所以自Unicode出现之后,字符集与字符编码需要明确区分开来。

    3.4 UTF-16编码的缺点

    UTF-16编码方式规定用两个或四个字节来表示所有的字符。对于ASCII字符保持不变,只是将原来的7位扩展到了16位,其高9位永远是0。如字符’A’:

    ASCII: 100 0001
    UTF-16: 0000 0000 0100 0001
    

    可以看到对于ASCII字符,UTF-16的存储空间扩大了一倍,UTF-16并不是完全兼容ASCII字符集。这对于那些ASCII字符集已经满足需求的西方国家来说完全是没必要的,而且ASCII字符经过UTF-16编码之后高字节始终是0,导致很多C语言函数(如strcpy,strlen)会将此字节视为字符串的结束符'\0',从而出现错误的计算结果。
    而且,UTF-16还存在大小端的问题,这里写图片描述(念suì)Unicode码在大端系统上为D852 DF62,小端系统上为52D8 62DF
    因此,UTF-16一开始推出的时候就遭到很多西方国家的抵制,影响了Unicode的推行。于是后来又设计了UTF-8编码方式,才解决了这些问题。

    3.5. Unicode字符集常用编码方式:UTF-8

    3.5.1 UTF-8概述

    UTF-8是互联网上使用最广泛的Unicode字符集编码方式。UTF-8编码的最小单位由8位(1个字节)组成,UTF-8使用一个至四个字节来表示Unicode字符。另外,UTF-8是完美兼容ASCII字符集的,这一点可以通过下面的UTF-8的编码规则得到证明。

    3.5.2 UTF-8编码规则

    UTF-8编码规则很简单:
    (1)对于ASCII(单字节字符)字符,采用和ASCII相同的编码方式,即只使用一个字节表示,且该字节第一位为0.
    (2)对于多字节(2~4字节)字符,假设字节数为n(1 < n <= 4),第一个字节:前n位都设为1,第n+1位设为0;后面的n-1个字节的前两位一律设为10。所有字节中的没有提及的其他二进制位,全部为这个符号的unicode码。
    这里写图片描述

    3.5.2 UTF-8 BOM

    BOM(byte order mark)从字面意义来看是标记字节顺序的。最早出现的原因是因为UTF-16和UTF-32编码采用2个或4个字节表示一个字符,面临大小端的问题。为了区分是使用的大端(Big Endian,简称BE)还是小端(Little Endian,简称LE),采用了在串的前面加入指定的字节加以区分,UTF-16大端加入FE FF,小端加入FF FE. 比如, 字符串“ABC”的UTF-16编码为 00 41 00 42 00 43,对应的各种的字节序列如下:
    这里写图片描述

    因为UTF-8和ASCII都是单字节序列,二者不好区分,微软采用在UTF-8编码的字符串前也加入BOM(3个字节EF BB BF)来标记UTF-8编码的串。UTF-8 BOM这一规范大多在windows下被使用,在其他平台下用的很少使用,如:Linux全部采用UTF-8编码,不存在要区分的情况;HTTP协议中可以包含Content-Type:text/html; charset=utf-8这样的说明,也不需要区分。

    展开全文
  • 文字编码

    千次阅读 2009-04-21 13:58:00
    在介绍文字编码之前,先来熟悉几个概念:字符和...字符编码:编码是指把字符转换为数字形式以在计算机中存储和使用的过程。从编程的角度将就是将字符转换为一个或多个字节来标示。 同样,解码就是将一个或多个字节组装

    在介绍文字编码之前,先来熟悉几个概念:

    1. 字符和字符集:这个很容易理解,就不多解释了。需要强调一点的是字符和字符集本身是不需要什么编码的。比如在没有计算机之前,我们照样可以说法,照样可以在纸上写各种各样的文字,这些都是不需要什么编码的。
    2. 字符编码:编码是指把字符转换为数字形式以在计算机中存储和使用的过程。从编程的角度将就是将字符转换为一个或多个字节来标示。 同样,解码就是将一个或多个字节组装为字符的过程。强调三点,编码是为了计算机的使用的; 二是编码都是数字的 ; 三是对同一个字符,可能存在好几种不同的编码
    3. 代码页:代码页规定了一个字符集中所有字符的数字编码
    4. 代码页转换表:在Windows中,默认采用Unicode编码。所以,当windows下的显示软件来显示文本信息时,需要调用windows API的相关函数来,从文件中取出一串字节串,这些字节串是按某种编码格式编码的,然后windows需要把这些转换为unicode的编码并最终显示在显示器上。因此,各种非unicode的编码需要有一个方案来转换为对应的unicode编码,这就是代码页转换表。
    5. ANSI: American National Stands Institute。美国国家标准协会。是ISO委员会的成员。
    6. 字符编码的兼容性:是指同一字符,在两种不同的编码方案中,编码是一样的。从ASCII、GB2312到GBK,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。 GBK和Unicode编码是不兼容的。但是可以根据一定的规则转换
    7. UCS只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可以用4个ascii数字来传输、保存这个编码;也可以用utf-8编码:3个连续的字节E6 B1 89来表示它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。UTF-8的一个特别的好处是它与ISO-8859-1完全兼容(ASCII)。UTF是“UCS Transformation Format”的缩写。
    8. Unicode 是 Universal Multiple-Octet Coded Character Set 的缩写。
      UCS 是 Universal Character Set(通用字符集)的缩写,即某一个整数表示哪个文字。
      UTF 全称是“UCS Transformation Format”,表示文件存储和数据传输时的具体格式,比如 95 这个数字,是用一个字节来存还是用两个字节来存,还是四个字节?
      UTF-8 用一个或多个字节存储一个整数。
      UTF-16 始终用两个字节存储一个整数。
      UTF-32 始终用四个字节存储一个整数。
    9. UTF的依据还是UCS的编码,只是在其基础上转化。

    文字的显示

    1.1 发生了什么?
    我们首先以Windows为例来看看文字显示过程中发生了什么。用记事本打开一个文本文件,可以看到文件包含的文字:

     

    下面是用WinHex打开的其在ANSI,Unicode,Unicode Big End, UTF-8编码下的字节内容:

    我们看到:ANSI格式编码的文件有10个字节,依次是“D7 D6 B7 FB BA CD B1 E0 C2 EB”,这就是记事本从文件中读到的内容。即文件中存储的是一串字节流
    记事本是用来打开文本文件的,所以它会调用Windows的文本显示函数将读到的数据作为文本显示。Windows首先将文本数据转换到它内部使用的编码格式:Unicode,然后按照文本的Unicode去字体文件中查找字体图像,最后将图像显示到窗口上。
    总结一下前面的分析,文字的显示应该是这样的:
    步骤1:文字首先以某种编码保存在文件中。
    步骤2:Windows将文件中的文字编码映射到Unicode。
    步骤3:Windows按照Unicode在字体文件中查找字体图像,画到窗口上。

    所谓编码就是用数字表示字符,例如用D7D6表示“字”。当然,编码还意味着约定,即大家都认可。从《谈谈Unicode编码》中,我们知道Unicode也是一种文字编码,它的特殊性在于它是由国际组织设计,可以容纳全世界所有语言文字。而我们平常使用的文字编码通常是针对一个区域的语言、文字设计,只支持特定的语言文字。

    如果上述3个步骤中任何一步发生了错误,文字就不能被正确显示,例如:
    错误1:如果弄错了编码,例如将Big5编码的文字当作GBK编码,就会出现乱码。


    错误2:如果从特定编码到Unicode的映射发生错误,例如文本数据中出现该编码方案未定义的字符,Windows就会使用缺省字符,通常是?。


    错误3:如果当前字体不支持要显示的字符,Windows就会显示字体文件中的缺省图像:空白或方格。

    在Unicode被广泛使用前,有多少种语言、文字,就可能有多少种文字编码方案。一种文字也可能有多种编码方案。那么我们怎么确定文本数据采用了什么编码?

    1.2 采用了哪种编码?
    按照惯例,文本文件中的数据都是文本编码,那么它怎么表明自己的编码格式?在记事本的“打开”对话框上

    我们可以看到记事本支持4种编码格式:ANSI、Unicode、Unicode big endian、UTF-8。其实它们更准确的名称应该是UTF-16LE(Little Endian)、UTF-16BE(Big Endian)和UTF-8,它们是基于Unicode的不同编码方案。

    Windows通过在文本文件开头增加一些特殊字节(BOM)来区分上述3种编码,并将没有BOM的文本数据按照ANSI代码页处理。那么什么是代码页,什么是ANSI代码页?

    2 代码页和字符集

    2.1代码页
    代码页(Code Page)是个古老的专业术语,据说是IBM公司首先使用的。代码页和字符集的含义基本相同,代码页规定了适用于特定地区的字符集合,和这些字符的编码。可以将代码页理解为字符和字节数据的映射表。
    Windows为自己支持的代码页都编了一个号码。例如代码页936就是简体中文 GBK,代码页950就是繁体中文 Big5。代码页的概念比较简单,就是一个字符编码方案。但要说清楚Windows的ANSI代码页,就要从Windows的区域(Locale)说起了。

    2.2 区域和ANSI代码页

    微软为了适应世界上不同地区用户的文化背景和生活习惯,在Windows中设计了区域(Locale)设置的功能。Local是指特定于某个国家或地区的一组设定,包括代码页,数字、货币、时间和日期的格式等。在Windows内部,其实有两个Locale设置:系统Locale和用户Locale。系统Locale决定代码页,用户Locale决定数字、货币、时间和日期的格式。我们可以在控制面板的“区域和语言选项”中设置系统Locale和用户Locale:

    每个Locale都有一个对应的代码页。系统Locale对应的代码页被作为Windows的默认代码页。在没有文本编码信息时,Windows按照默认代码页的编码方案解释文本数据。这个默认代码页通常被称作ANSI代码页(ACP)。
    ANSI代码页还有一层意思,就是微软自己定义的代码页。在历史上,IBM的个人计算机和微软公司的操作系统曾经是PC的标准配置。微软公司将IBM公司定义的代码页称作OEM代码页,在IBM公司的代码页基础上作了些增补后,作为自己的代码页,并冠以ANSI的字样。我们在“区域和语言选项”高级页面的代码页转换表中看到的包含ANSI字样的代码页都是微软自己定义的代码页。例如:
    874 (ANSI/OEM - 泰文)
    932 (ANSI/OEM - 日文 Shift-JIS)
    936 (ANSI/OEM - 简体中文 GBK)
    949 (ANSI/OEM - 韩文)
    950 (ANSI/OEM - 繁体中文 Big5)
    1250 (ANSI - 中欧)
    1251 (ANSI - 西里尔文)
    1252 (ANSI - 拉丁文 I)
    1253 (ANSI - 希腊文)
    1254 (ANSI - 土耳其文)
    1255 (ANSI - 希伯来文)
    1256 (ANSI - 阿拉伯文)
    1257 (ANSI - 波罗的海文)
    1258 (ANSI/OEM - 越南)
    我们不能直接设置ANSI代码页,只能通过选择系统Locale,间接改变当前的ANSI代码页。微软定义的Locale只使用自己定义的代码页。所以,我们虽然可以通过“区域和语言选项”中的代码页转换表安装很多代码页,但只能将微软的代码页作为系统默认代码页。

    2.3 代码页转换表
    在Windows 2000以后,Windows统一采用UTF-16作为内部字符编码。现在,安装一个代码页就是安装一张代码页转换表。通过代码页转换表,Windows既可以将代码页的编码转换到UTF-16,也可以将UTF-16转换到代码页的编码。代码页转换表的具体实现可以是一个以nls为后缀的数据文件,也可以是一个提供转换函数的动态链接库。有的代码页是不需要安装的。例如:Windows将UTF-7和UTF-8分别作为代码页65000和代码页65001。UTF-7、UTF-8和UTF-16都是基于Unicode的编码方案。它们之间可以通过简单的算法直接转换,不需要安装代码页转换表。
    在安装过一个代码页后,Windows就知道怎样将该代码页的文本转换到Unicode文本,也知道怎样将Unicode文本转换成该代码页的文本。
    其实,如果全世界人民在计算机刚发明时就统一采用Unicode作为字符编码,那么代码页就没有存在的必要了。可惜在Unicode被发明前,世界各国人民都发明并使用了各种字符编码方案。所以,Windows必须通过代码页支持已经被广泛使用的字符编码。从这种意义看,代码页主要是为了兼容现有的数据、程序和习惯而存在的。

    2.4 SBCS、DBCS和MBCS
    SBCS、DBCS和MBCS分别是单字节字符集、双字节字符集和多字节字符集的缩写。SBCS、DBCS和MBCS的最大编码长度分别是1字节、两字节和大于两字节(例如4或5字节)。例如:代码页1252 (ANSI-拉丁文 I)是单字节字符集;代码页936 (ANSI/OEM-简体中文 GBK)是双字节字符集;代码页54936 (GB18030 简体中文)是多字节字符集。
    单字节字符集中的字符都用一个字节表示。显然,SBCS最多只能容纳256个字符。
    双字节字符集的字符用一个或两个字节表示。那么我们从文本数据中读到一个字节时,怎么判断它是单字节字符,还是双字节字符的首字符?答案是通过字节所处范围来判断。例如:在GBK编码中,单字节字符的范围是0x00-0x80,双字节字符首字节的范围是0x81到0xFE。我们顺序读取字节数据,如果读到的字节在0x81到0xFE内,那么这个字节就是双字节字符的首字节。GBK定义双字节字符的尾字节范围是0x40到0x7E和0x80到0xFE。
    GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。这时我们又如何判断一个字节是属于单字节字符,双字节字符,还是四字节字符?GB18030与GBK是兼容的,它利用了GBK双字节字符尾字节的未使用码位。GB18030的四字节字符的第一字节的范围也是0x81到0xFE,第二字节的范围是0x30-0x39。通过第二字节所处范围就可以区分双字节字符和四字节字符。GB18030定义四字节字符的第三字节范围是0x81到0xFE,第四字节范围是0x30-0x39

     

    原帖地址:http://blog.csdn.net/fmddlmyy/archive/2007/02/14/1510189.aspx

     

    展开全文
  • 字符编码那些事--彻底理解掌握编码知识

    万次阅读 多人点赞 2020-05-04 16:42:33
    每一个程序员都不可避免的遇到字符编码的问题,很多人在字符编码方面同样遇到不少问题,而且一直对各种编码懵懵懂懂、不清不楚。这篇文章就是针对字符编码中的一些问题进行了详细的阐述,能从根本上理解字符编码

    一、讲述之前我们先来了解一些概念

    1、字符

    字符指类字形单位或符号,包括字母、数字、运算符号、标点符号和其他符号,以及一些功能性符号。一般来说我们称某个字符集里面的字符,叫xx字符,如ASCII字符集里面的ASCII字符,GB2312字符集里面的GB2312字符。

    2、字符集

    字符集(Character Set、Charset),字面上的理解就是字符的集合,是一个自然语言文字系统支持的所有字符的集合。字符是各种文字和符号的总称,包括文字、数字、字母、音节、标点符号、图形符号等。例如ASCII字符集,定义了128个字符;GB2312字符集定义了7445个字符。而字符集准确地来说,指的是已编号的字符的有序集合(但不一定是连续的,后文有详细介绍)。
    常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。

    3、码位

    在字符编码术语中,码位(code point)或称编码位置、码点,是组成码空间(或代码页)的数值。 例如,ASCII码包含128个码位,范围是016进制到7F16进制,扩展ASCII码包含256个码位,范围是016进制到FF16进制,而Unicode包含1,114,112个码位,范围是016进制到10FFFF16进制。Unicode码空间划分为17个Unicode字符平面(基本多文种平面,16个辅助平面),每个平面有65,536(= 216)个码位。因此Unicode码空间总计是17 × 65,536 = 1,114,112. —解释来源于维基百科

    4、字符编码

    字符编码(Character Encoding),是把字符集中的字符按一定方式编码为某指定集合中的某一对象的过程(比如将字符编码为由0和1两个数字所组成的位串模式、由0~9十个数字所组成的自然数序列或电脉冲等),亦即在字符集与指定集合两者之间建立一个对应关系(即映射关系)的过程。这是信息处理的一项基础技术。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII码。
    p.s.这里我们计算机这里字符编码肯定是用二进制来编码的
    看完这四个概念,你应该要明白,它们之间的关系,以ASCII为例,下图解释它们之间关系
    在这里插入图片描述
    这里细说一下,码位就是这个字符集里面字符的一个表示位置,通俗来说,码位就是一般跟字符集绑在一起,字符编码是把字符集中的字符编码为特定的二进制数,以便在计算机中存储。这个二进制数就叫xx码。

    二、字符集编码分类总结

    在说字符集编码之前,先明确一个观点,字符集编码与字符集是两个不同层面的概念:
    (1)charset 是 character set 的简写,即字符集。
    (2)encoding 是 charset encoding 的简写,即字符集编码,简称编码
    在这里插入图片描述

    1、ASCII编码

    ASCII(美国信息交换标准代码)是基于拉丁字母(就是我们现在的英文字母)的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本延伸美国标准信息交换码则可以部分支持其他西欧语言,并等同于国际标准ISO/IEC 646。

    ASCII 由电报码发展而来。第一版标准发布于1963年,1967年经历了一次主要修订,最后一次更新则是在1986年,至今为止共定义了128个字符;其中33个字符无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符。控制字符的用途主要是用来操控已经处理过的文字。在33个字符之外的是95个可显示的字符。用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。

    每个ASCII字符占用1个字节(8bits),共有128位字符或符号,使用7位二进制数(剩下的1位二进制为0,即高位为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符。

    缺点:ASCII的最大缺点是只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语(而且在处理英语当中的外来词如naïve、café、élite等等时,所有重音符号都不得不去掉,即使这样做会违反拼写规则)。而EASCII(即扩展的ASCII码,利用8位的高位设为1进行扩展)虽然解决了部份西欧语言的显示问题,但对更多其他语言依然无能为力。因此现在的操作系统内码(稍后会讲)基本已经抛弃ASCII码而转用Unicode码。

    ASCII码表 :http://www.asciitable.com

    2、GB2312编码

    前面可以看到ASCII码即使进行了扩展也能表示的字符也很少,尤其是当需要计算机显示存储中文的时候,就需要一种对中文进行编码的字符集,GB 2312就是解决中文编码的字符集,由国家标准委员会发布。那个时候当中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存,于是想到把那些ASCII码中127号之后的奇异符号们直接取消掉, 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。这种汉字方案叫做 “GB2312”。GB2312 是对 ASCII 的中文扩展。兼容ASCII。
    在这里插入图片描述
    这里的A GB2312码是0xA3C1,0xA3和0xC1都是高于127的,所以判断它是个全角字符,另外我们可以观察到所有的GB2312编码表中的GB2312码每个字节都是大于0xA0的,这个就是为了保证能区分是否为ASCII码,小于127的字节就按照ASCII码标准,碰到连续两个大于127字节就组合成一个GB2312码。

    GB2312汉字编码字符集对照表:http://tools.jb51.net/table/gb2312

    3、GBK编码

    但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来,不得不继续把 GB2312 没有用到的码位找出来用上。后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 “GBK” 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。

    4、GB18030编码

    后来中国的少数民族也要用电脑了,GBK的两万多字也已经无法满足我们的需求了,还有更多可能你自己从来没见过的汉字需要编码。这时候显然只用2bytes表示一个字已经不够用了(2byte最多只有65536种组合,然而为了和ASCII兼容,最高位不能为0就已经直接淘汰了一半的组合,只剩下3万多种组合无法满足全部汉字要求)。因此GB18030多出来的汉字使用4byte编码。当然,为了兼容GBK,这个四字节的前两位显然不能与GBK冲突(实操中发现后两位也并没有和GBK冲突)。通过多年的发展至此,GB18030编码的中文文件已经有七万多个汉字了。

    GB18030包含三种长度的编码:单字节的ASCII、双字节的GBK(略带扩展)、以及用于填补所有Unicode码位的四字节UTF区块。所以我们说GB18030采用多字节编码,每个字符可以由 1 个、2 个或 4 个字节组成。

    其实我们用到的99%以上的汉字,都在GB2312那一块区域内。在实际使用中,GBK编码已经可以满足大部分场景了,GB18030编码中所有汉字都是我们这辈子都不一定能见到的文字,所以平时经常会使用的就是GBK编码。

    这里额外总结一下这四个兼容性关系是GB18030兼容GBK,GBK兼容GB2312,GB2312兼容ASCII。所谓兼容,你可以简单理解为子集、不冲突的关系。例如GB2312编码的文件中可以出现ASCII字符,GBK编码的文件中可以出现GB2312和ASCII字符,GB18030编码的文件可以出现GBK、GB2312、ASCII字符。

    5、Unicode

    友情建议:看Unicode一些概念解释和历史时,建议看维基百科,而且是英文版的,别用中文版,有些地方讲的模棱两可,容易陷入盲区。

    Unicode(中文:万国码、国际码、统一码、单一码)(全称Universal Multiple-Octet Coded Character Set)它伴随着通用字符集(英语:Universal Character Set, UCS)的标准而发展。所以可以看出他是字符集。

    1.Unicode与ISO 10646

    全世界很多个国家都在为自己的文字编码,并且互不相通,不同的语言字符编码值相同却代表不同的符号(例如:韩文编码EUC-KR中“한국어”的编码值正好是汉字编码GBK中的“茄惫绢”)。因此,同一份文档,拷贝至不同语言的机器,就可能成了乱码,于是人们就想:我们能不能定义一个超大的字符集,它可以容纳全世界所有的文字字符,再对它们统一进行编码,让每一个字符都对应一个不同的编码值,从而就不会再有乱码了。如果说“各个国家都在为自己文字独立编码”是百家争鸣,那么“建立世界统一的字符编码”则是一统江湖,谁都想来做这个武林盟主。早前就有两个机构做了这个事:
    (1) 国际标准化组织(ISO),他们于1984年创建ISO/IEC JTC1/SC2/WG2工作组,试图制定一份“通用字符集”(Universal Character Set,简称UCS),并最终制定了ISO 10646标准。(简单来说ISO 10646标准就是UCS)
    (2) 统一码联盟,他们由Xerox、Apple等软件制造商于1988年组成,并且开发了Unicode标准(The Unicode Standard,这个前缀Uni很牛逼哦—Unique, Universal, and Uniform)。

    Unicode与ISO 10646标准的风风雨雨:

    在1984年,喜欢以繁多的编号糊弄群众的国际标准化组织ISO也开始着手制定解决不同语言字符数量太大问题的解决方案,这一方案被称为Universal Character Set(UCS),正式的编号是ISO-10646(记得么,ASCII是ISO-646,不知这种安排是否是故意的)。还是ISO高瞻远瞩,一开始就确定了UCS是一个31位的编码字符集(即用一个大小不超过2的31次方的整数数字为每个字符编号),这回真的足以容纳古往今来所有国家,所有语言所包含的字符了(是的,任何国家,任何小语种都包括)。虽然后来他们意识到,2的31次方个码位又实在太多了……

    天下大势,分久必合。无论Unicode还是UCS,最初的目的都是杜绝各种各样名目繁多形式各异互不兼容老死不相往来的私用扩展编码(好啰嗦的一句话),结果两方确立标准的同时(最初时这两个标准是不兼容的),因为都是个干个的,肯定不可能一模一样,出现标准不同。1991年,Unicode联盟与ISO的工作组终于开始讨论Unicode与UCS的合并问题,虽然其后的合并进行了很多年,Unicode初版规范中的很多编码都需要被改写,UCS也需要对码空间的使用进行必要限制,但成果是喜人的。最终,两者统一了抽象字符集(即任何一个在Unicode中存在的字符,在UCS中也存在),且最靠前的65535个字符也统一了字符的编码。对于码空间,两者同意以一百一十万为限(即两者都认为虽然65536不够,但2的31次方又太大,一百一十万是个双方都可接受的码空间大小,也够用,当然,这里说的一百一十万只是个约数),Unicode将码空间扩展到了一百一十万,而UCS将永久性的不使用一百一十万以后的码位。也就是说,现在再讲Unicode只包含65536个字符是不对的(虽然大家现在都知道Unicode至少都可以囊括几亿个字符)。除了对已经定义的字符进行统一外,Unicode联盟与ISO工作组也同意今后任何的扩展工作两者均保持同步,因此虽然从历史的意义上讲Unicode与UCS不是一回事(甚至细节上说也不是一回事),但现在提起Unicode,指代两者均无不妥,毕竟因为已经统一了。(现在网上基本上把Unicode字符集叫做UCS,Unicoide 的全称是 Universal Multiple-Octet Coded Character Set简写也是UCS,一看也对上了,害,只能说天注定)

    现在Unicode编码点分为17个平面(plane),每个平面包含216(即65536)个码位(code point)。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0016到1016,共计17个平面。

    这第一个位置(当xx是00的时候)被称为BMP(基本多文种平面,BasicMultilingualPlane)。它包含了最常用的码位从U+0000到U+FFFF(常见的65536个字符)

    其余16个平面(从下面的1号平面到16号平面),你可以叫做非BMP,由此这样分的话里面的字符就有两个概念:BMP字符和非BMP字符,后者也被称为补充字符。(偷偷告诉你们,大家喜闻乐见的Emoji表情都是在1号平面,范围是U+1F600-U+1F64F)
    在这里插入图片描述
    2. UCS-2和UCS-4

    ISO 10646标准为“通用字符集”(UCS)定义了一种16位的编码形式(即UCS-2),UCS-2全称Universal Character Set coded in 2 octets,从英文上就可以看出含义,以2字节编码的通用字符集编码,固定占用2个字节,它包含65536个编码空间(可以为全世界最常用的63K字符编码,为了兼容Unicode,0xD800-0xDFFF之间的码位未使用)。例:“汉”的UCS-2编码为6C49。除此之外ISO 10646标准为“通用字符集”(UCS)还定义了一种31位的编码形式(即UCS-4),UCS-4全称Universal Character Set coded in 4 octets,其编码固定占用4个字节,编码空间为0x00000000 ~0x7FFFFFFF(可以编码20多亿个字符)。随着Unicode与ISO 10646合并统一,Unicode就用UCS通用字符集标准,早期的Unicode编码实现也就采用了UCS-2和UCS-4。(准确来说是UCS-2,UCS-4基本上是理论,没付诸实际,毕竟早期65536个字符已经够用了,我两个字节编码能实现的事,脑子笨的人才会用四个字节实现,你以为存储和带宽有多的)
    在这里插入图片描述这里编码最多也就存在UCS-2(big Endian和Little Endian先不管,后面会讲)

    Unicode字符集只规定了码点和文字之间的对应关系,并没有规定码点在计算机中如何存储。UCS-2和UCS-4就规定了具体的实现,后来改进演变为了UTF-16, UTF-32。然后又创造了一种全新的简单粗暴好用的变长编码UTF-8,于是乎这三哥们就形成了现代Unicode字符集编码实现的三剑客

    3. UTF-16与UTF-32

    Unicode与ISO 10646合并统一后,Unicode与 ISO 10646 的通用字符集概念(UCS)相对应。早期实现Unicode用的编码是UCS-2,后来随着发展发现 216(即 65536)个字符不能满足了,Unicode标准本身发生了变化:65536个字符显得不足,引入了更大的31位空间和一个编码(UCS-4),每个字符需要4个字节。前面已经介绍了。但是统一码联盟对此予以抵制(这就是为什么我之前说UCS-4是一种理论编码,根本就没付诸实际),这是因为每个字符4个字节浪费了很多磁盘空间和内存,并且因为一些制造商已经在每个字符2个字节的技术上投入了大量资金。所以最后通过一系列巴拉巴拉讨论规定形成了一种折衷方案,建立了UTF-16编码方案(此时Unicode标准2.0),它替代了原有的UCS-2,并做了改进。它与UCS-2一样,它使用两个字节为全世界最常用的63K字符编码,不同的是,它使用4个字节对不常用的字符进行编码。目的就是为了支持从17个平面编码1,112,064个代码点。UTF-16属于变长编码。我们可以将UTF-16编码看成是UCS-2编码父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-2所指的是同一意思。但当引入辅助平面字符后,就称为UTF-16了。现在应该认为UCS-2已作废,如果有人还用这种,也不必纠结,它就是表达用定长2字节编码,自己心里清楚就行(基本上你查维基百科上UCS-2都是重定向到UTF-16)。另外当时ISO 10646的UCS-4编码并入了Unicode标准,而UCS-4有20多亿个编码空间,但实际使用范围并不超过0x10FFFF,并且为了兼容Unicode标准,ISO也承诺将不会为超出0x10FFFF的UCS-4编码赋值。由此提出了实实在在的UTF-32编码(现在也应该认为UCS-4像UCS-2一样作废,维基百科上UCS-4也重定向到UTF-32页面),它的编码值与UCS-4相同,只不过其编码空间被限定在了0~0x10FFFF之间。因此也可以说:UTF-32是UCS-4的一个子集。

    (现在若有软件声称自己支持UCS-2,那其实是暗指它不能支持在UTF-16中超过2字节的字集。)

    UTF-16(16 位 Unicode转换格式)是一种字符编码,能够对Unicode的所有1,112,064个有效码点进行编码(实际上,此代码点数由UTF-16的设计决定,这个你细品你就知道什么意思,就好像某个班有55个人,根据55个座位确定55个人,而55个座位这个多少是由55个人决定的,两者是相互的,这是一个哲学道理,hh扯远了,所以其中意味自行明白)。
    前面提到过:Unicode编码点分为17个平面(plane),每个平面包含216(即65536)个码位(code point),而第一个平面称为“基本多语言平面”(Basic Multilingual Plane,简称BMP),其余平面称为“辅助平面”(Supplementary Planes)。其中“基本多语言平面”(00xFFFF)中0xD8000xDFFF之间的码位作为保留,未使用。UCS-2只能编码“基本多语言平面”中的字符,此时UTF-16与UCS-2的编码一样(都直接使用Unicode的码位作为编码值),例:“汉”在Unicode中的码位为6C49,而在UTF-16编码也为6C49。另外,UTF-16还可以利用保留下来的0xD800-0xDFFF区段的码位来对“辅助平面”的字符的码位进行编码,因此UTF-16可以为Unicode中所有的字符编码。

    UTF-16和UTF-32也就是如今Unicode编码的标准之二,他们的区别就是UTF-16是变长编码,大部分是2字节和少部分4字节,UTF-32是定长编码,表示任何字符都用 4 字节

    4. UTF-8

    从前述内容可以看出:无论是UCS-2/4还是UTF-16/32,一个字符都需要多个字节来编码,这对那些英语国家来说多浪费带宽啊!(尤其在网速本来就不快的那个年代。。。),而且我们注意到UTF-16最少2字节和UTF-32不变4字节,这肯定是不兼容ASCII码的,由此,UTF-8产生了。在UTF-8编码中,ASCII码中的字符还是ASCII码的值,只需要一个字节表示,其余的字符需要2字节、3字节或4字节来表示。

    UTF-8的编码规则:
    (1) 对于ASCII码中的符号,使用单字节编码,其编码值与ASCII值相同。其中ASCII值的范围为0~0x7F,所有编码的二进制值中第一位为0(这个正好可以用来区分单字节编码和多字节编码)。
    (2) 其它字符用多个字节来编码(假设用N个字节),多字节编码需满足:第一个字节的前N位都为1,第N+1位为0,后面N-1 个字节的前两位都为10,这N个字节中其余位全部用来存储Unicode中的码位值。
    在这里插入图片描述
    现如今UTF-8 是互联网上使用最广的一种 Unicode 的实现方式,是其他两种无可比拟的(详情请看这篇文章)

    5.UTF的字节序和BOM
    字节序就要先补充一点知识:
    码元(code unit):是能用于处理或交换编码文本的最小比特组合。它代表某种编码中最小的可用来识别一个合法字符的最小字节数序列

    UTF-8使用变长的字节序列来表示字符;某个字符(对应一个码点)可能使用1-4个字节才能表示;在UTF-8中一个字符最小可能一个字节,所以我们规定1个字节就是一个码元;

    UTF-16使用也变长字节序列来表示字符;某个字符(对应一个码点)可能使用2个或者4个字符来表示;因为2个字节序列是最小的能够识别一个码点的单位,同理我们规定2个字节就是一个码元;

    UTF-32使用定长的4个字节表示一个字符;一个字符(对应一个码点)使用4个字符来表示,这样4个字节就是一个码元。

    简单来说,就是“码点”经过映射后得到的二进制串的转换格式单位称之为“码元”。“码点”就是一串二进制数,“码元”就是切分这个二进制数的方法。这些编码每次处理一个码元,你可以把它理解为UTF-8每次读码点的8位,UTF-16每次读码点的16位,UTF-32每次读码点的32位,。当然这也是为什么叫这些叫Unicode转换格式的原因。处理的是同一个字符集,但是处理方式不同。

    字节序
    UTF-8一次一个UTF-8码元,即处理一个字节,没有字节序的问题。UTF-16一次处理一个UTF-16码元,对应两个字节,UTF-32一次一个UTF-32码元,对应处理四个字节,所以这就要考虑到一个字节序问题。以UTF-16w为例,在解释一个UTF-16编码文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?这就考虑大小端问题,所以UTF-16编码包括三种:UTF-16BE(Big Endian),UTF-16LE(Little Endian)、UTF-16(类似的名称UCS-2BE和UCS-2LE用于显示UCS-2的版本。)

    UTF-16BE和UTF-16LE好理解,直接指定了字节序(大小端),但是UTF-16怎么处理呢?

    Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

    在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。

    同样的类比,UTF-32也是这样的。有UTF-32BE、UTF-32LE、UTF-32。前面UTF-32BE和UTF-32LE直接指定了字节序(大小端),后面的UTF-32也是靠BOM。

    UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

    Windows就是使用BOM来标记文本文件的编码方式的。它就建议所有的 Unicode 文件应该以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符开头。这作为一个“特征符”或“字节顺序标记(byte-order mark,BOM)”来识别文件中使用的编码和字节顺序。所以用Windows自带的记事本将文件保存为UTF-8编码的时候,记事本会自动在文件开头插入BOM(虽然BOM对UTF-8来说并不是必须的)。但也有一些系统或程序不支持BOM,因此带有BOM的Unicode文件有时会带来一些问题。比如JDK1.5以及之前的Reader都不能处理带有BOM的UTF-8编码的文件,解析这种格式的xml文件时,会抛出异常:Content is not allowed in prolog。Linux/UNIX 并没有使用 BOM,因为它会破坏现有的 ASCII 文件的语法约定。 所以一般我们不建议用Windows自带的记事本编辑UTF-8文件就是这样。

    6. 总结
    (1) 简单地说:Unicode和UCS是字符集,不属于编码UTF-8、UTF-16、UTF-32等是针对Unicode字符集的编码,UCS-2和UCS-4是针对UCS字符集的编码(只是我们习惯把Unicode字符集编码简称为Unicode编码,把UCS字符集编码称为UCS编码)。 Unicode沿用UCS字符集,在UCS-2和UCS-4基础上提出的UTF-16、UTF-32。并发展了UTF-8,发展到现在,就密不可分了,大家基于UCS就把Uniocde维护好就行,发布标准大家统一。以往的UCS-2和UCS-4概念就默认作废了这样一个关系,整个他们的发展长话短说就是这样,懂了吗。
    (2) UTF-8、UTF-16、UTF-32、UCS-2、UCS-4对比:
    在这里插入图片描述
    由于历史方面的原因,你还会在不少地方看到把Unicode称为一种编码的情况,那是因为早期的2字节编码最初称为“ Unicode”,但现在称为“ UCS-2”,这种情况下的 Unicode 通常就是 UTF-16 或者是更早的 UCS-2 编码,只是被一直搞混了,在某些老软件上尤为常见。比如下面editplus里面文件编码设置。
    在这里插入图片描述
    以前的Windows电脑上的记事本(左边)显示的是Unicode,不过现在好像改了变成了UTF-16。
    在这里插入图片描述
    不过由于各种原因,必须承认,在不同的语境下,“Unicode”这个词有着不同的含义。
    它可能指:
    (1)Unicode 标准
    (2)Unicode 字符集
    (3)Unicode 的抽象编码(编号),也即码点、码位(code point)
    (4)Unicode 的一个具体编码实现,通常即为变长的 UTF-16(16 或 32 位),又或者是更早期的定长 16 位的 UCS-2

    所以像我一般有时候非要区分的话都是直接说全,Unicode 标准,Unicode 字符集,Unicode编码等等。你们呢QAQ

    6、ANSI编码

    为使计算机支持更多语言,通常使用0x800~xFF范围的2个字节来表示1个字符。比如:汉字 ‘中’ 在中文操作系统中,使用 [0xD6,0xD0]这两个字节存储。
    不同的国家和地区制定了不同的标准,由此产生了 GB2312、GBK、GB18030、Big5、Shift_JIS 等各自的编码标准。这些使用多个字节来代表一个字符的各种语言延伸编码方式,称为 ANSI 编码。在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在繁体中文Windows操作系统中,ANSI编码代表Big5;在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码。

    不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
    在使用ANSI编码支持多语言阶段,每个字符使用一个字节或多个字节来表示(MBCS,Multi-Byte Character System),因此,这种方式存放的字符也被称作多字节字符。比如,“中文123” 在中文 Windows 95 内存中为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节。

    在非 Unicode 环境下,由于不同国家和地区采用的字符集不一致,很可能出现无法正常显示所有字符的情况。微软公司使用了代码页(Codepage)转换表的技术来过渡性的部分解决这一问题,即通过指定的转换表将非 Unicode 的字符编码转换为同一字符对应的系统内部使用的Unicode 编码。可以在“语言与区域设置”中选择一个代码页作为非 Unicode 编码所采用的默认编码方式,如936为简体中文GBK,950为正体中文Big5(皆指PC上使用的)。在这种情况下,一些非英语的欧洲语言编写的软件和文档很可能出现乱码。而将代码页设置为相应语言中文处理又会出现问题,这一情况无法避免。从根本上说,完全采用统一编码才是解决之道,虽然现在Unicode有了,但由于历史遗留,老软件等等原因,所以系统统一用某种编码格式的Unicode目前尚无法做到这一点。

    代码页技术现在广泛为各种平台所采用。UTF-7 的代码页是65000,UTF-8 的代码页是65001。简体中文上使用的代码页为936,GBK编码。

    以前中文DOS、中文/日文Windows 95/98时代系统内码使用的是ANSI编码(本地化,根据不同地区设置不同的系统内码Windows版本),现在win7,win10等等系统的内码都是用的Unicode,不过微软为了以前的程序兼容性,比如在某些情况下,比如你的程序需要和不支持Unicode的程序交互时,可能还是会需要用到code page,提供代码页服务(就好比微软不能说:“老子支持unicode了,以后不支持Unicode的程序都给我滚粗。”只能撅着屁股让这些老掉牙的程序仍然可以运行,于是只好给他们提供一个“非Unicode默认字符集”) 。可以在cmd下输入chcp查看code page。
    在这里插入图片描述

    • Windows API 的 Wide Char 表达是 UTF-16: Unicode (Windows), L"" 表示是转换为 wide char。
    • Cocoa 的 NSString 和 Core Foundation 的 CFString 内部表达都是 UTF-16,所以其实 OS X 和 iOS 内部处理都用的是 UTF-16。
    • Java String 的内部表达是 UTF-16,所以大量跨平台程序和 Android 程序其实内部也在用 UTF-16。
    • 大部分的操作系统和 UI framework 的内部字符串表达(内码)都是UTF-16,不过Linux系统内使用的内码是UTF-8

    7、Tip:内码和外码

    在计算机科学及相关领域当中,内码指的是“将信息编码后,透过某种方式存储在特定记忆设备时,设备内部的编码形式”。在不同的系统中,会有不同的内码。

    在以往的英文系统中,内码为ASCII。 在繁体中文系统中,当前常用的内码为大五码。在简体中文系统中,内码则为国标码。
    为了软件开发方便,如国际化与本地化,现在许多系统会使用Unicode做为内码,常见的操作系统Windows、Mac OS X、Linux皆如此。许多编程语言也采用Unicode为内码,如Java、Python3。

    外码:除了内码,皆是外码。要注意的是,源代码编译产生的目标代码文件(如果Java可执行文件或class文件)中的编码方式属于外码。

    8、参考文章,引用文章如下:

    必读,真说清的话得结合上面的维基百科上的说法理解:
    https://en.wikipedia.org/wiki/Universal_Coded_Character_Set

    https://en.wikipedia.org/wiki/Unicode

    https://en.wikipedia.org/wiki/UTF-16

    https://en.wikipedia.org/wiki/UTF-32

    除此之外参考引用了下面三篇文章的一些观点:
    http://www.blogjava.net/zhenandaci/archive/2008/12/24/248014.html

    https://www.cnblogs.com/malecrab/p/5300503.html

    https://blog.51cto.com/polaris/377468
    还有一些其他文章的资料就不一一列举了。

    展开全文
  • 拨开字符编码的迷雾--字符编码转换

    万次阅读 2017-11-27 21:22:09
    1. Windows API介绍本文介绍使用Windows API进行字符编码的转换,涉及WideCharToMultiByte和MultiByteToWideChar2个API, API接口名中的MultiByte对应着多字节编码,如ASCII、UTF-8等都是多字节编码,而WideChar...
  • 要了解乱码的症结,我们就得从字符集和字符编码说起,先来看看它们到底是什么: 1:字符集:是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。 2:...
  • 字库表、编码字符集、字符编码

    千次阅读 2019-05-09 08:50:14
    1、十分钟搞清字符集和字符编码 2、字符编码与字符集的区别 字库表(character repertoire):相当于一个 所有 可读或者可显示字符的数据库。其决定了编码字符集能够展示的字符的范围。 编码字符集(coded ...
  • 文章目录数据校验字符编码本质字符编码类别介绍多媒体格式 本篇主要是对计算机常识中的信息编码方面的知识进行学习的总结的第二部分 上一篇传送门 数据校验 后面再补齐 字符编码 本质 计算机存储介质中实际存储的都...
  • 也谈计算机字符编码 值得收藏 1) 每种ANSI编码或者说ANSI字符集只规定自己国家或地区使用的语言所需的'字符';比如中文GB-2312编码中就不会包含韩国人的文字。 2) ANSI字符集的空间都比ASCII要大很多,一个字节已经...
  • 字符编码小记

    千次阅读 2016-02-03 14:19:54
    字符编码”分为 字符集 和 编码方案 两个含义。
  • C++与字符集、字符编码

    千次阅读 2019-11-02 10:50:06
    字符编码 字符集与字符编码的关系 多种字符编码存在的意义 字符编码的发展历史 活动代码页 c++的多字节字符与宽字节字符 c++的多字节字符串与宽字节字符串 C++程序输出字符串的编码 字符串常量 参考文章 ...
  • 字符编码研究

    千次阅读 2015-11-20 23:07:48
    字符编码研究  应用开发中,经常会遇到乱码的问题,对于新手尤其如此。为了原理乱码问题带来的困扰,特整理一下字符编码的原理,从根本上杜绝乱码的出现。 一,相关概念  在计算机的世界中,所有的信息都是由01...
  • 本文介绍了MySQL数据库中默认字符编码的设置方法,如何设置与修改mysql默认编码,my.ini设置字符编码的教程,需要的朋友参考下。 本节重点: mysql基础配置之mysql的默认字符编码的设置(my.ini设置字符编码) ...
  • 结合Java详谈字符编码和字符集

    万次阅读 多人点赞 2018-07-07 14:04:45
    字符编码和字符集是两个基础性的概念,很多开发人员对其都并不陌生,但是很少有人能将其讲得很准确。当应用出现乱码时,如何分析和定位原因,很多人仍是一头雾水。这篇文章,将从字符编码和字符集的相关概念开始讲解...
  • 单字节编码: 双字节编码: 多字节编码
  • 字符编码杂谈

    千次阅读 2017-07-20 10:40:03
    字符编码杂谈基础知识准备字符编码笔记:ASCII,Unicode和UTF-8准备工具notepad++添加16进制插件Unicode与UTF-8的异同 Unicode只是一个符号集,它只规定了符号的二进制代码,而不是二进制代码的一种存储方式。而utf-...
  • 谷歌浏览器字符编码插件
  • Python中的字符串与字符编码 本节内容: 前言相关概念Python中的默认编码Python2与Python3中对字符串的支持字符编码转换 一、前言 Python中的字符编码是个老生常谈的话题,同行们都写过很多这方面的文章。...
  • C语言字符编码

    千次阅读 2019-04-11 15:55:02
    以C语言程序在windows控制台中的输入输出为例,阐述程序在执行环境中字符编码的过程: 1.假设用户键入拼音nihao,那么输入法根据用户输入的拼音,给出字符候选列表。 2.用户阅读完候选列表后从中选择词语“你好” 3....
  • 字符集和字符编码1.1 编码和解码1.2 字节和字符1.2 实验环境2. 安装过程2.1 Python 和 Django2.2 PostGIS2.3 psycopg22.4 PROJ.4,GDAL和GEOS2.5 配置环境变量3. 测试GeoDjango3.1 准备3.2 创建新项目3.2 查看地理...
  • 字符编码详解

    千次阅读 2017-04-03 17:19:29
    看到一篇很用心讲字符编码的文章,另外推荐《编码》一书(英文原名《CODE:The Hidden Language of Computer Hardware and Software》) 原文地址 版本:v2.3.1 CrifanLi 摘要 本文主要介绍了字符...
  • 火狐浏览器设置字符编码格式

    千次阅读 2020-06-03 10:48:26
    今天浏览html页面时出现乱码,查了一下如何改火狐浏览器的编码的方式,很多是老版的了...修改字符编码 直接通过菜单 –> 更多 –> 文字编码 点击文字编码就可以选择自己的想要的编码格式了。 修改后的样子 ...
  • 计算机中目前最普遍使用的汉字字符编码是ASCII码,它是用七位二进制数进行编码的,可表示128个字符。ASCII码是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。计算机中目前最普遍使用的汉字...
  • 一. Visual Studio字符集 ...但这个设置项不会对编译器处理字符编码产生直接的影响(注意这里的“直接”二字,第3节会说到),只会在工程属性配置属性-->C/C++-->预处理器加入相应的宏: 使用Unicode字符集 --
  • 关于文字编码

    千次阅读 2012-03-04 16:32:35
    文字编码属于字符编码,这里先阐述一下字符编码的背景知识   编码:编码是将信息从一种形式或格式转换为另一种形式的过程,这里的文字编码是指把字符转换为数字形式(即将字形转换成一个或多个字节来显示)从而...
  • oracle 修改字符编码

    千次阅读 2019-04-03 12:02:56
    1. 问题描述 在安装oracle时设置的编码是ZHS16GBK , ...这时需要修改oracle的字符编码 2. 解决问题 第一步: 查看oracle的字符编码 SQL> select * from v$nls_parameters; PARAMETER VALUE --------...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,243,633
精华内容 497,453
关键字:

文字编码