精华内容
下载资源
问答
  • 拨开字符编码的迷雾--字符编码概述

    万次阅读 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系列字符集经历下面的几个发展过程:

    编码名称 发布时间 字节数 汉字范围
    GB2312 1980年 变字节(ASCII 1字节,汉字2个字节) 6763个汉字
    GB13000 1993年第一版 变字节(ASCII 1字节,汉字2个字节) 20902个汉字
    GBK Windows95中 2个字节 21886个汉字和图形符号(含GB2312,BIG5中所有字符)
    GB18030 2000年第一版 变字节(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这样的说明,也不需要区分。

    展开全文
  • 字符编码

    千次阅读 2015-12-25 19:25:59
    1、什么是字符编码?  我们知道,计算机数据只能是二进制的,数值类型的数据转换成二进制很简单,我们已经了解了,但字符类型如何转换成二进制呢?这就需要使用字符编码!  在编码表中,每个字符都有对应的编码,...

    1、什么是字符编码?


      我们知道,计算机数据只能是二进制的,数值类型的数据转换成二进制很简单,我们已经了解了,但字符类型如何转换成二进制呢?这就需要使用字符编码!

      在编码表中,每个字符都有对应的编码,编码是整数,最终在计算机中存储的是字符的编码,而不是字符本身(因为计算机数据都是二进制数值,所以字符本身是无法存储的)。

      当我们存储字符’A’时,其实是通过编码表找到’A’字符对应的编码,然后把编码存储在计算机中。即存储的是65。当我们读取字符时,其实读取的也是字符的编码,然后使用编码再去编码表中查找对应的字符显示。如下:


    2、常见的字符编码

    (1)ASCII

      在所有字符集中,最知名的可能要数被称为ASCII的7位字符集了。它是美国标准信息交换代码(American Standard Code for Information Interchange)的缩写, 为美国英语通信所设计。它由128个字符组成,包括大小写字母、数字0-9、标点符号、非打印字符(换行符、制表符等4个)以及控制字符(退格、响铃等)组成。

    (2)ISO-8859-1

      由于ASCII是针对英语设计的,当处理带有音调标号(形如汉语的拼音)的欧洲文字时就会出现问题。因此,创建出了一些包括255个字符的由ASCII扩展的字符集。有一种8位字符集是ISO 8859-1Latin 1,也简称为ISO Latin-1。它把位于128-255之间的字符用于拉丁字母表中特殊语言字符的编码,起初称为拉丁码,后来被ISO(国际标准化组织)命名为ISO-8859-1。

    (3)GB2312、GBK、GB18030

      GB2312是一个简体中文字符集的中国国家标准,全称为《信息交换用汉字编码字符集•基本集》,又称为GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。

      GB2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时,GB 2312收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。

      对于人名、古汉语等方面出现的罕用字,GB2312不能完全包括,于是对其进行了扩展,增加一些生僻字,形成了GBK。后来在GBK的基础上又增加了一些生僻字,就是GB18030。所以说,GB18030包括GBK,GBK包括GB2312。

      GB2312兼容ASCII码,这部分还是每个字符占1个字节。每个汉字字符占2个字节。GB2312是中国自己的字符集,而其他国家也都有自己的字符集!!!

    (4)Unicode

      很多国家针对自己的语言都拥有自己的字符编码,那么不同编码形式进行交互时就有可能导致不兼容,如果我们打开一份字节序文件,如果不知道其编码规则,就无法正确解析其语义,这也是产生乱码的根本原因。于是有人就想将世界上的字符全部统一在一个编码表中,这就出现了Unicode编码。

      Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的编码,以满足跨语言、跨平台进行文本转换、处理的要求。它通过增加一个高字节(2个字节)对ISO Latin-1字符集进行扩展,当这些高字节位为0时,低字节就是ISO Latin-1字符。UNICODE支持欧洲、非洲、中东、亚洲(包括统一标准的东亚象形汉字和韩国象形文字)。但是,UNICODE并没有提供对诸如Braille, Cherokee, Ethiopic 文字的支持。同时它也不支持如Ahom, Akkadian, Aramaic, Babylonian Cuneiform之类的古老文字。Unicode支持ISO Latin-1(ISO-8859-1),而Latin-1包含了ASCII编码表。

      记住:Unicode是一个统一的编码规范,UTF-8是Unicode的一种实现方式,Unicode的实现方式除了UTF-8还有其它的,比如UCS-2和UTF-16等,它们之间能够互相转换。

    3、Unicode 下的几种实现方式

    (1)UTF-8

      最初的unicode编码是固定长度的,16位,也就是2两个字节代表一个字符,这样一共可以表示65536个字符。显然,这样要表示各种语言中所有的字符是远远不够的。Unicode4.0规范考虑到了这种情况,定义了一组附加字符编码,附加字符编码采用2个16位来表示,这样最多可以定义1048576个附加字符,目前unicode4.0只定义了45960个附加字符。

      事实证明,对可以用ASCII表示的字符使用UNICODE并不高效,因为UNICODE比ASCII占用大一倍的空间,而对ASCII来说高字节的0对他毫无用处。为了解决这个问题,就出现了一些中间格式的字符集,他们被称为通用转换格式,即UTF(Universal Transformation Format)。目前存在的UTF格式有:UTF-7, UTF-7.5, UTF-8, UTF-16, 以及 UTF-32。

      话说当初大牛Ben Thomson吃饭时,在一张餐巾纸上,设计出了UTF-8,然后回到房间,实现了第一版的UTF-8。

      UTF-8是一种8位的unicode字符集,编码长度是可变的,并且是ASCII字符集的严格超集,也就是说ASCII中每个字符的编码在UTF-8中是完全一样的。UTF-8字符集中,一个字符可能是1个字节,2个字节,3个字节或者4个字节长。一般来说,欧洲的字母字符长度为1到2个字节,而亚洲的大部分字符则是3个字节,附加字符为4个字节长。所以说,UTF-8能对不同范围的字符使用不同长度的编码,例如ASCII 编码部分与ASCII一样,都是1个字节,而汉字部分就是3个字节。

      UTF-8的主要优点:

        对于欧洲字母字符需要较少的存储空间。

        容易从ASCII字符集向UTF-8迁移。

    (2)UCS-2

      UCS-2是固定长度为16位的unicode字符集。每个字符都是2个字节,UCS-2只支持unicode3.0,所以不支持附加字符。

      UCS-2的优点:

        对于亚洲字符的存储空间需求比UTF-8少,因为每个字符都是2个字节。

        处理字符的速度比UTF-8更快,因为是固定长度编码的。

        对于windows和java的支持更好。

    (3)UTF-16

      UTF-16也是一种16位编码的字符集。实际上,UTF-16就是UCS-2加上附加字符的支持,也就是符合unicode4.0规范的UCS-2。所以UTF-16是UCS-2的严格超集。UTF-16中的字符,要么是2个字节,要么是4个字节表示的。UTF-16主要在windows2000以上版本使用。

    4、Unicode转换到UTF-8规则

       如果Unicode编码的16位二进制数的前9位是0, 则UTF-8编码用一个字节来表示,这个字节的首位是0,剩下的7位与原二进制数据的后7位相同。例如:

      Unicode编码:\u0061 = 00000000 01100001

      UTF-8编码: 01100001 = 0x61

       如果Unicode编码的16位二进制数的头5位是0,则UTF-8编码用2个字节来表示,首字节用110开头,后面的5位与原二进制数据去掉前5个零后的最高5位相同;第二个字节以10开头,后面的6位与原二进制数据的低6位数据相同。例如:

      Unicode编码: \u00A9 = 00000000 10101001

      UTF-8编码: 11000010 10101001 = 0xC2  0xA9

       如果不符合上述两个规则,则用3个字节表示。第一个字节以1110开头,后四位为原二进制数据的高四位,第二个字节以10开头,后六位为原二进制数据的中间6位,第三个字节以10开头,后6位为原二进制数据的低6位。例如:

      Unicode编码: \u4E2D = 01001110 00101101

      UTF-8编码: 11100100 10111000 10101101 = 0xE4 0xB8 0xAD

    5、解释一下高字节和低字节

      16位是两个字节,前八位是高字节,后八位是低字节。当一个逻辑上长于一个字节的整形数据放置在内存中时(比如16位,32位,和64位的整数),计算机设计者需要考虑这些字节的存储顺序。一些设计者选择了将字节的逻辑顺序与物理顺序一致,即将逻辑上较低的字节放置在物理上较低的字节上;另一些设计者则选择了将字节的逻辑顺序与物理顺序相反,即将逻辑上较低的字节放置在物理上较高的字节上。

      ● Big-Endian 是指高字节存放在高地址,如下:

    内存地址 存放内容
     0x4000 
    0x12
    0x4001
    0x34

      ● littele-Endian 指高字节存放在第地址,如下:

    内存地址 
    存放内容
    0x4000
    0x34
    0x4001
    0x12 

      小结:字符编码就是将字符转换为二进制编码,其中Unicode是统一的编码规范,旗下有UTF-8等多种实现方式,而乱码的出现,就是因为使用了错误的编码表造成的!!!


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

    万次阅读 2017-11-27 21:22:09
    1. Windows API介绍本文介绍使用Windows API进行字符编码的转换,涉及WideCharToMultiByte和MultiByteToWideChar2个API, API接口名中的MultiByte对应着多字节编码,如ASCII、UTF-8等都是多字节编码,而WideChar...

    1. Windows API介绍

    本文介绍使用Windows API进行字符编码的转换,涉及WideCharToMultiByteMultiByteToWideChar2个API,
    API接口名中的MultiByte对应着多字节编码,如ASCII、UTF-8等都是多字节编码,而WideChar字面意思是宽字符,在windows内部宽字符特指UTF-16编码。 原型如下:

    int WideCharToMultiByte(
      UINT CodePage, 
      DWORD dwFlags, 
      LPCWSTR lpWideCharStr, 
      int cchWideChar, 
      LPSTR lpMultiByteStr, 
      int cbMultiByte, 
      LPCSTR lpDefaultChar, 
      LPBOOL lpUsedDefaultChar 
    );
    
    int MultiByteToWideChar(
      UINT CodePage, 
      DWORD dwFlags, 
      LPCSTR lpMultiByteStr, 
      int cbMultiByte, 
      LPWSTR lpWideCharStr, 
      int cchWideChar 
    );
    

    2. 接口封装

    std::string UnicodeToANSI(const std::wstring &str, UINT iCodePage = CP_ACP) {
        std::string strRes;
        int iSize = ::WideCharToMultiByte(iCodePage, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
    
        if (iSize == 0)
            return strRes;
    
        char *szBuf = new (std::nothrow) char[iSize];
        if (!szBuf)
            return strRes;
        memset(szBuf, 0, iSize);
    
        ::WideCharToMultiByte(iCodePage, 0, str.c_str(), -1, szBuf, iSize, NULL, NULL);
    
        strRes = szBuf;
        delete[] szBuf;
    
        return strRes;
    }
    
    std::wstring ANSIToUnicode(const std::string &str, UINT iCodePage = CP_ACP) {
        std::wstring strRes;
    
        int iSize = ::MultiByteToWideChar(iCodePage, 0, str.c_str(), -1, NULL, 0);
    
        if (iSize == 0)
            return strRes;
    
        wchar_t *szBuf = new (std::nothrow) wchar_t[iSize];
        if (!szBuf)
            return strRes;
        memset(szBuf, 0, iSize * sizeof(wchar_t));
    
        ::MultiByteToWideChar(iCodePage, 0, str.c_str(), -1, szBuf, iSize);
    
        strRes = szBuf;
        delete[] szBuf;
    
        return strRes;
    }
    
    std::string UnicodeToUTF8(const std::wstring &str) {
        std::string strRes;
    
        int iSize = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
    
        if (iSize == 0)
            return strRes;
    
        char *szBuf = new (std::nothrow) char[iSize];
        if (!szBuf)
            return strRes;
        memset(szBuf, 0, iSize);
    
        ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, szBuf, iSize, NULL, NULL);
    
        strRes = szBuf;
        delete[] szBuf;
    
        return strRes;
    }
    
    std::string UnicodeToUTF8BOM(const std::wstring &str) {
        std::string strRes;
    
        int iSize = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
    
        if (iSize == 0)
            return strRes;
    
        unsigned char *szBuf = new (std::nothrow) unsigned char[iSize + 3];
        if (!szBuf)
            return strRes;
        memset(szBuf, 0, iSize + 3);
    
        if (::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, (LPSTR)(szBuf + 3), iSize, NULL, NULL) > 0) {
            szBuf[0] = 0xEF;
            szBuf[1] = 0xBB;
            szBuf[2] = 0xBF;
        }
    
        strRes = (char*)szBuf;
        delete[] szBuf;
    
        return strRes;
    }
    
    std::wstring UTF8ToUnicode(const std::string &str) {
        std::wstring strRes;
        int iSize = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
    
        if (iSize == 0)
            return strRes;
    
        wchar_t *szBuf = new (std::nothrow) wchar_t[iSize];
        if (!szBuf)
            return strRes;
        memset(szBuf, 0, iSize * sizeof(wchar_t));
        ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, szBuf, iSize);
    
        strRes = szBuf;
        delete[] szBuf;
    
        return strRes;
    }
    
    std::string ANSIToUTF8(const std::string &str, UINT iCodePage = CP_ACP) {
        return UnicodeToUTF8(ANSIToUnicode(str, iCodePage));
    }
    
    std::string ANSIToUTF8BOM(const std::string &str, UINT iCodePage = CP_ACP) {
        return UnicodeToUTF8BOM(ANSIToUnicode(str, iCodePage));
    }
    
    std::string UTF8ToANSI(const std::string &str, UINT iCodePage = CP_ACP) {
        return UnicodeToANSI(UTF8ToUnicode(str), iCodePage);
    }
    

    对于只支持简体中文(部分韩文、日文)的系统,iCodePage可以使用CP_ACP,这时API会使用系统当前的代码页(简体中文系统为CP936,即GBK字符集)来进行编码转换。 但遇到如下情况就需要手动指定代码页了:
    1. 需要转换的字符串中的文字是系统当前代码页不支持的。如字符串中含有中文,而当前系统代码页确是英文的;
    2. GBK字符集中只包含了一部分韩文和日文,部分韩文和日文的转换可以正常转换,若遇到不能转换的情况也需要将指定iCodePage为特定的支持韩文或日文的代码页了,特别是中文和韩文、日文等混合的情况下。如韩文“탉”不包含在GBK中,若这时仍然使用CP_ACP就会得到错误的转换结果?,十六进制3F。但GB18030(代码页为54936)支持“탉”,可以手动指定iCodePage为54936。

    如果代码中含有GBK不支持的字符,如“탉”、这里写图片描述(念suì)等,Visual Studio会弹出如下提示:
    这里写图片描述
    选择“以其他编码保存”,选择“Unicode(UTF-8带签名)- 代码页65001”保存。
    虽然“简体中文(GB18030) - 代码页54936”也支持这些字符,但不能选择该选项进行保存,具体原因在拨开字符编码的迷雾–编译器如何处理文件编码 中有详细的介绍。

    展开全文
  • 关于字符编码,你所需要知道的

    千次阅读 2013-11-27 15:01:53
    字符编码的问题看似很小,经常被技术人员忽视,但是很容易导致一些莫名其妙的问题。这里总结了一下字符编码的一些普及性的知识,希望对大家有所帮助。 还是得从ASCII码说起   说到字符编码,不得不说ASCII码的...

    字符编码的问题看似很小,经常被技术人员忽视,但是很容易导致一些莫名其妙的问题。这里总结了一下字符编码的一些普及性的知识,希望对大家有所帮助。

    还是得从ASCII码说起

     

    说到字符编码,不得不说ASCII码的简史。计算机一开始发明的时候是用来解决数字计算的问题,后来人们发现,计算机还可以做更多的事,例如文本处理。但由于计算机只识“数”,因此人们必须告诉计算机哪个数字来代表哪个特定字符,例如65代表字母‘A’,66代表字母‘B’,以此类推。但是计算机之间字符-数字的对应关系必须得一致,否则就会造成同一段数字在不同计算机上显示出来的字符不一样。因此美国国家标准协会ANSI制定了一个标准,规定了常用字符的集合以及每个字符对应的编号,这就是ASCII字符集(Character Set),也称ASCII码。

    当时的计算机普遍使用8比特字节作为最小的存储和处理单元,加之当时用到的字符也很少,26个大小写英文字母还有数字再加上其他常用符号,也不到100个,因此使用7个比特位就可以高效的存储和处理ASCII码,剩下最高位1比特被用作一些通讯系统的奇偶校验。

    注意,字节代表系统能够处理的最小单位,不一定是8比特。只是现代计算机的事实标准就是用8比特来代表一个字节。在很多技术规格文献中,为了避免产生歧义,更倾向于使用8位组(Octet)而不是字节(Byte)这个术语来强调8个比特的二进制流。下文中为了便于理解,我会延用大家熟悉的“字节”这个概念。

    ASCII table

    ASCII字符集由95个可打印字符(0x20-0x7E)和33个控制字符(0x00-0x19,0x7F)组成。可打印字符用于显示在输出设备上,例如荧屏或者打印纸上,控制字符用于向计算机发出一些特殊指令,例如0x07会让计算机发出哔的一声,0x00通常用于指示字符串的结束,0x0D和0x0A用于指示打印机的打印针头退到行首(回车)并移到下一行(换行)。

    那时候的字符编解码系统非常简单,就是简单的查表过程。例如将字符序列编码为二进制流写入存储设备,只需要在ASCII字符集中依次找到字符对应的字节,然后直接将该字节写入存储设备即可。解码二进制流的过程也是类似。

    OEM字符集的衍生

    当计算机开始发展起来的时候,人们逐渐发现,ASCII字符集里那可怜的128个字符已经不能再满足他们的需求了。人们就在想,一个字节能够表示的数字(编号)有256个,而ASCII字符只用到了0x00~0x7F,也就是占用了前128个,后面128个数字不用白不用,因此很多人打起了后面这128个数字的主意。可是问题在于,很多人同时有这样的想法,但是大家对于0x80-0xFF这后面的128个数字分别对应什么样的字符,却有各自的想法。这就导致了当时销往世界各地的机器上出现了大量各式各样的OEM字符集。

    下面这张表是IBM-PC机推出的其中一个OEM字符集,字符集的前128个字符和ASCII字符集的基本一致(为什么说基本一致呢,是因为前32个控制字符在某些情况下会被IBM-PC机当作可打印字符解释),后面128个字符空间加入了一些欧洲国家用到的重音字符,以及一些用于画线条画的字符。

    IBM-PC OEM字符集

    事实上,大部分OEM字符集是兼容ASCII字符集的,也就是说,大家对于0x00~0x7F这个范围的解释基本是相同的,而对于后半部分0x80~0xFF的解释却不一定相同。甚至有时候同样的字符在不同OEM字符集中对应的字节也是不同的。

    不同的OEM字符集导致人们无法跨机器交流各种文档。例如职员甲发了一封简历résumés给职员乙,结果职员乙看到的却是rגsumגs,因为é字符在职员甲机器上的OEM字符集中对应的字节是0x82,而在职员乙的机器上,由于使用的OEM字符集不同,对0x82字节解码后得到的字符却是ג

    多字节字符集(MBCS)和中文字符集

    上面我们提到的字符集都是基于单字节编码,也就是说,一个字节翻译成一个字符。这对于拉丁语系国家来说可能没有什么问题,因为他们通过扩展第8个比特,就可以得到256个字符了,足够用了。但是对于亚洲国家来说,256个字符是远远不够用的。因此这些国家的人为了用上电脑,又要保持和ASCII字符集的兼容,就发明了多字节编码方式,相应的字符集就称为多字节字符集。例如中国使用的就是双字节字符集编码(DBCS,Double Byte Character Set)。

    对于单字节字符集来说,代码页中只需要有一张码表即可,上面记录着256个数字代表的字符。程序只需要做简单的查表操作就可以完成编解码的过程。

    代码页是字符集编码的具体实现,你可以把他理解为一张“字符-字节”映射表,通过查表实现“字符-字节”的翻译。下面会有更详细的描述。

    而对于多字节字符集,代码页中通常会有很多码表。那么程序怎么知道该使用哪张码表去解码二进制流呢?答案是,根据第一个字节来选择不同的码表进行解析

    例如目前最常用的中文字符集GB2312,涵盖了所有简体字符以及一部分其他字符;GBK(K代表扩展的意思)则在GB2312的基础上加入了对繁体字符等其他非简体字符(GB18030字符集不是双字节字符集,我们在讲Unicode的时候会提到)。这两个字符集的字符都是使用1-2个字节来表示。Windows系统采用936代码页来实现对GBK字符集的编解码。在解析字节流的时候,如果遇到字节的最高位是0的话,那么就使用936代码页中的第1张码表进行解码,这就和单字节字符集的编解码方式一致了。

    image

    当字节的高位是1的时候,确切的说,当第一个字节位于0x81–0xFE之间时,根据第一个字节不同找到代码页中的相应的码表,例如当第一个字节是0x81,那么对应936中的下面这张码表:

    image

    (关于936代码页中完整的码表信息,参见MSDN:http://msdn.microsoft.com/en-us/library/cc194913%28v=MSDN.10%29.aspx.)

    按照936代码页的码表,当程序遇到连续字节流0x81 0x40的时候,就会解码为“丂”字符。

    ANSI标准、国家标准、ISO标准

    不同ASCII衍生字符集的出现,让文档交流变得非常困难,因此各种组织都陆续进行了标准化流程。例如美国ANSI组织制定了ANSI标准字符编码(注意,我们现在通常说到ANSI编码,通常指的是平台的默认编码,例如英文操作系统中是ISO-8859-1,中文系统是GBK),ISO组织制定的各种ISO标准字符编码,还有各国也会制定一些国家标准字符集,例如中国的GBK,GB2312和GB18030。

    操作系统在发布的时候,通常会往机器里预装这些标准的字符集还有平台专用的字符集,这样只要你的文档是使用标准字符集编写的,通用性就比较高了。例如你用GB2312字符集编写的文档,在中国大陆内的任何机器上都能正确显示。同时,我们也可以在一台机器上阅读多个国家不同语言的文档了,前提是本机必须安装该文档使用的字符集。

    Unicode的出现

    虽然通过使用不同字符集,我们可以在一台机器上查阅不同语言的文档,但是我们仍然无法解决一个问题:在一份文档中显示所有字符。为了解决这个问题,我们需要一个全人类达成共识的巨大的字符集,这就是Unicode字符集。

    Unicode字符集概述

    Unicode字符集涵盖了目前人类使用的所有字符,并为每个字符进行统一编号,分配唯一的字符码(Code Point)。Unicode字符集将所有字符按照使用上的频繁度划分为17个层面(Plane),每个层面上有216=65536个字符码空间。

    image

    其中第0个层面BMP,基本涵盖了当今世界用到的所有字符。其他的层面要么是用来表示一些远古时期的文字,要么是留作扩展。我们平常用到的Unicode字符,一般都是位于BMP层面上的。目前Unicode字符集中尚有大量字符空间未使用。

    编码系统的变化

    在Unicode出现之前,所有的字符集都是和具体编码方案绑定在一起的,都是直接将字符和最终字节流绑定死了,例如ASCII编码系统规定使用7比特来编码ASCII字符集;GB2312以及GBK字符集,限定了使用最多2个字节来编码所有字符,并且规定了字节序。这样的编码系统通常用简单的查表,也就是通过代码页就可以直接将字符映射为存储设备上的字节流了。例如下面这个例子:

    image

    这种方式的缺点在于,字符和字节流之间耦合得太紧密了,从而限定了字符集的扩展能力。假设以后火星人入住地球了,要往现有字符集中加入火星文就变得很难甚至不可能了,而且很容易破坏现有的编码规则。

    因此Unicode在设计上考虑到了这一点,将字符集和字符编码方案分离开。

    字符编码系统

    也就是说,虽然每个字符在Unicode字符集中都能找到唯一确定的编号(字符码,又称Unicode码),但是决定最终字节流的却是具体的字符编码。例如同样是对Unicode字符“A”进行编码,UTF-8字符编码得到的字节流是0x41,而UTF-16(大端模式)得到的是0x00 0x41。

    常见的Unicode编码

    UCS-2/UTF-16

    如果要我们来实现Unicode字符集中BMP字符的编码方案,我们会怎么实现?由于BMP层面上有216=65536个字符码,因此我们只需要两个字节就可以完全表示这所有的字符了。

    举个例子,“中”的Unicode字符码是0x4E2D(01001110 00101101),那么我们可以编码为01001110 00101101(大端)或者00101101 01001110 (小端)。

    UCS-2和UTF-16对于BMP层面的字符均是使用2个字节来表示,并且编码得到的结果完全一致。不同之处在于,UCS-2最初设计的时候只考虑到BMP字符,因此使用固定2个字节长度,也就是说,他无法表示Unicode其他层面上的字符,而UTF-16为了解除这个限制,支持Unicode全字符集的编解码,采用了变长编码,最少使用2个字节,如果要编码BMP以外的字符,则需要4个字节结对,这里就不讨论那么远,有兴趣可以参考维基百科:UTF-16/UCS-2

    Windows从NT时代开始就采用了UTF-16编码,很多流行的编程平台,例如.Net,Java,Qt还有Mac下的Cocoa等都是使用UTF-16作为基础的字符编码。例如代码中的字符串,在内存中相应的字节流就是用UTF-16编码过的。

    UTF-8

    UTF-8应该是目前应用最广泛的一种Unicode编码方案。由于UCS-2/UTF-16对于ASCII字符使用两个字节进行编码,存储和处理效率相对低下,并且由于ASCII字符经过UTF-16编码后得到的两个字节,高字节始终是0x00,很多C语言的函数都将此字节视为字符串末尾从而导致无法正确解析文本。因此一开始推出的时候遭到很多西方国家的抵触,大大影响了Unicode的推行。后来聪明的人们发明了UTF-8编码,解决了这个问题。

    UTF-8编码方案采用1-4个字节来编码字符,方法其实也非常简单。

    image

    (上图中的x代表Unicode码的低8位,y代表高8位)

    对于ASCII字符的编码使用单字节,和ASCII编码一摸一样,这样所有原先使用ASCII编解码的文档就可以直接转到UTF-8编码了。对于其他字符,则使用2-4个字节来表示,其中,首字节前置1的数目代表正确解析所需要的字节数,剩余字节的高2位始终是10。例如首字节是1110yyyy,前置有3个1,说明正确解析总共需要3个字节,需要和后面2个以10开头的字节结合才能正确解析得到字符

    关于UTF-8的更多信息,参考维基百科:UTF-8

    GB18030

    任何能够将Unicode字符映射为字节流的编码都属于Unicode编码。中国的GB18030编码,覆盖了Unicode所有的字符,因此也算是一种Unicode编码。只不过他的编码方式并不像UTF-8或者UTF-16一样,将Unicode字符的编号通过一定的规则进行转换,而只能通过查表的手段进行编码。

    关于GB18030的更多信息,参考:GB18030

    Unicode相关的常见问题

    Unicode是两个字节吗?

    Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体存储为什么样的字节流,取决于字符编码方案。推荐的Unicode编码是UTF-16和UTF-8。

    带签名的UTF-8指的是什么意思?

    带签名指的是字节流以BOM标记开始。很多软件会“智能”的探测当前字节流使用的字符编码,这种探测过程出于效率考虑,通常会提取字节流前面若干个字节,看看是否符合某些常见字符编码的编码规则。由于UTF-8和ASCII编码对于纯英文的编码是一样的,无法区分开来,因此通过在字节流最前面添加BOM标记可以告诉软件,当前使用的是Unicode编码,判别成功率就十分准确了。但是需要注意,不是所有软件或者程序都能正确处理BOM标记,例如PHP就不会检测BOM标记,直接把它当普通字节流解析了。因此如果你的PHP文件是采用带BOM标记的UTF-8进行编码的,那么有可能会出现问题。

    Unicode编码和以前的字符集编码有什么区别?

    早期字符编码、字符集和代码页等概念都是表达同一个意思。例如GB2312字符集、GB2312编码,936代码页,实际上说的是同个东西。但是对于Unicode则不同,Unicode字符集只是定义了字符的集合和唯一编号,Unicode编码,则是对UTF-8、UCS-2/UTF-16等具体编码方案的统称而已,并不是具体的编码方案。所以当需要用到字符编码的时候,你可以写gb2312,codepage936,utf-8,utf-16,但请不要写unicode(看过别人在网页的meta标签里头写charset=unicode,有感而发)。

     

    乱码问题

    乱码指的是程序显示出来的字符文本无法用任何语言去解读。一般情况下会包含大量?或者�。乱码问题是所有计算机用户或多或少会遇到的问题。造成乱码的原因就是因为使用了错误的字符编码去解码字节流因此当我们在思考任何跟文本显示有关的问题时,请时刻保持清醒:当前使用的字符编码是什么。只有这样,我们才能正确分析和处理乱码问题。

    例如最常见的网页乱码问题。如果你是网站技术人员,遇到这样的问题,需要检查以下原因:

    • 服务器返回的响应头Content-Type没有指明字符编码
    • 网页内是否使用META HTTP-EQUIV标签指定了字符编码
    • 网页文件本身存储时使用的字符编码和网页声明的字符编码是否一致  

    image image

    注意,网页解析的过程如果使用的字符编码不正确,还可能会导致脚本或者样式表出错。具体细节可以参考我以前写过的文章:文档字符集导致的脚本错误Asp.Net页面的编码问题

    不久前看到某技术论坛有人反馈,WinForm程序使用Clipboard类的GetData方法去访问剪切板中的HTML内容时会出现乱码的问题,我估计也是由于WinForm在获取HTML文本的时候没有用对正确的字符编码导致的。Windows剪贴板只支持UTF-8编码,也就是说你传入的文本都会被UTF-8编解码。这样一来,只要两个程序都是调用Windows剪切板API编程的话,那么复制粘贴的过程中不会出现乱码。除非一方在获取到剪贴板数据之后使用了错误的字符编码进行解码,才会得到乱码(我做了简单的WinForm剪切板编程实验,发现GetData使用的是系统默认编码,而不是UTF-8编码)。

    关于乱码中出现?或者�,这里需要额外提一下,当程序使用特定字符编码解析字节流的时候,一旦遇到无法解析的字节流时,就会用?或者�来替代。因此,一旦你最终解析得到的文本包含这样的字符,而你又无法得到原始字节流的时候,说明正确的信息已经彻底丢失了,尝试任何字符编码都无法从这样的字符文本中还原出正确的信息来

    必要的术语解释

    字符集(Character Set),字面上的理解就是字符的集合,例如ASCII字符集,定义了128个字符;GB2312定义了7445个字符。而计算机系统中提到的字符集准确来说,指的是已编号的字符的有序集合(不一定是连续)

    字符码(Code Point)指的就是字符集中每个字符的数字编号。例如ASCII字符集用0-127这连续的128个数字分别表示128个字符;GBK字符集使用区位码的方式为每个字符编号,首先定义一个94X94的矩阵,行称为“区”,列称为“位”,然后将所有国标汉字放入矩阵当中,这样每个汉字就可以用唯一的“区位”码来标识了。例如“中”字被放到54区第48位,因此字符码就是5448。而Unicode中将字符集按照一定的类别划分到0~16这17个层面(Planes)中,每个层面中拥有216=65536个字符码,因此Unicode总共拥有的字符码,也即是Unicode的字符空间总共有17*65536=1114112。

    image

    编码的过程是将字符转换成字节流。

    解码的过程是将字节流解析为字符。

    字符编码(Character Encoding)是将字符集中的字符码映射为字节流的一种具体实现方案。例如ASCII字符编码规定使用单字节中低位的7个比特去编码所有的字符。例如‘A’的编号是65,用单字节表示就是0x41,因此写入存储设备的时候就是b’01000001’。GBK编码则是将区位码(GBK的字符码)中的区码和位码的分别加上0xA0(160)的偏移(之所以要加上这样的偏移,主要是为了和ASCII码兼容),例如刚刚提到的“中”字,区位码是5448,十六进制是0x3630,区码和位码分别加上0xA0的偏移之后就得到0xD6D0,这就是“中”字的GBK编码结果。

    代码页(Code Page)一种字符编码具体形式。早期字符相对少,因此通常会使用类似表格的形式将字符直接映射为字节流,然后通过查表的方式来实现字符的编解码。现代操作系统沿用了这种方式。例如Windows使用936代码页、Mac系统使用EUC-CN代码页实现GBK字符集的编码,名字虽然不一样,但对于同一汉字的编码肯定是一样的。

    大小端的说法源自《格列佛游记》。我们知道,鸡蛋通常一端大一端小,小人国的人们对于剥蛋壳时应从哪一端开始剥起有着不一样的看法。同样,计算机界对于传输多字节字(由多个字节来共同表示一个数据类型)时,是先传高位字节(大端)还是先传低位字节(小端)也有着不一样的看法,这就是计算机里头大小端模式的由来了。无论是写文件还是网络传输,实际上都是往流设备进行写操作的过程,而且这个写操作是从流的低地址向高地址开始写(这很符合人的习惯),对于多字节字来说,如果先写入高位字节,则称作大端模式。反之则称作小端模式。也就是说,大端模式下,字节序和流设备的地址顺序是相反的,而小端模式则是相同的。一般网络协议都采用大端模式进行传输。

    展开全文
  • 字库表、编码字符集、字符编码

    千次阅读 2019-05-09 08:50:14
    1、十分钟搞清字符集和字符编码 2、字符编码与字符集的区别 字库表(character repertoire):相当于一个 所有 可读或者可显示字符的数据库。其决定了编码字符集能够展示的字符的范围。 编码字符集(coded ...
  • 关于各种常用字符编码

    千次阅读 2012-12-30 22:16:06
    这是最早的一种编码,很多其他的编码都会兼容ascii编码,ascii编码只包含常用的英文字母,数字,以及一些特殊字符,还有部分控制字符。 每个字符由占用一个字节的存储空间,因为最多只包含127个字符,而一个字节(8...
  • MySQL字符集和校对规则MySQL的字符集是用来定义MySQL存储字符串的方式,校对规则(有的软件叫排序规则)则是用来定义了比较字符串的方式。字符集和校对规则是一对多的关系。每种字符集都有一个默认校对规则。查看...
  • C++与字符集、字符编码

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

    千次阅读 2017-08-03 13:13:01
    在windows机器上用记事本写了一个错误日志,再在linux用vim打开中文出现乱码, 问题:记事本默认编码ANSI /(Unicoded,Unicode big endian,utf-8) vim 默认字符集为 utf-8 资料 查看TXT文件编码方式: 首先...
  • 上周游戏突发一个严重的漏洞,玩家通过在聊天世界频道发送€符号,会导致接下来发言的玩家看到的内容混乱,这种捣乱的行为,我立即去查了一下,发现这是引擎在处理字符编码时的一个错误导致的,这个错误非常隐蔽,以...
  • 关于Unicode,字符集,字符编码

    千次阅读 2017-12-21 23:08:01
    由一套用于特定用途的字符组成,例如支持西欧语言的字符集合,支持中文的字符集合。字符集合只定义了符号和他们的语意,其实跟计算机没有直接关系。 现实生活中,不同的语系有自己的字符集合,例如藏文有自己的字符...
  • 字符编码研究

    千次阅读 2015-11-20 23:07:48
    字符编码研究  应用开发中,经常会遇到乱码的问题,对于新手尤其如此。为了原理乱码问题带来的困扰,特整理一下字符编码的原理,从根本上杜绝乱码的出现。 一,相关概念  在计算机的世界中,所有的信息都是由01...
  • 结合Java详谈字符编码和字符集

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

    千次阅读 2014-01-06 19:21:31
    1 关于多字节与宽字符的解释 非英语系的大部分语言,存在无法用有限的ascii字符表达的问题。 由此产生了使用多字节字符来表示的办法,比如GB编码的汉字。 但多字节带来的一个显著不便就是多字节字符在处理的时候不太...
  • 腾讯大讲堂——字符编码的前世今生 字符串,那些你不知道的事 编码字符集标准及分类研究 通信用語の基礎知識 —— ISO/IEC 2022 ISO 2022 介紹(1): 標準 1. 说明 1.1 字符编码贡献的相关的组织 1.2 ...
  • 字符编码的问题看似很小,经常被技术人员忽视,但是很容易导致一些莫名其妙的问题。这里总结了一下字符编码的一些普及性的知识,希望对大家有所帮助。还是得从ASCII码说起   说到字符编码,不得不...
  • Python中的字符串与字符编码 本节内容: 前言相关概念Python中的默认编码Python2与Python3中对字符串的支持字符编码转换 一、前言 Python中的字符编码是个老生常谈的话题,同行们都写过很多这方面的文章。...
  • 关于字符编码(linux终端显示中文)

    千次阅读 2012-04-18 13:47:10
    今天在CSDN的Blog首页看到一篇文章“也谈计算机字符编码 ”,由于前一阵业余翻译了“UTF-8 and Unicode FAQ for Unix/Linux”一文,自己对字符集、编码和Unicode等内容一直保着者很强的兴趣,自然不会放过这样的文章...
  • 字符编码详解

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

    千次阅读 2019-04-11 15:55:02
    以C语言程序在windows控制台中的输入输出为例,阐述程序在执行环境中字符编码的过程: 1.假设用户键入拼音nihao,那么输入法根据用户输入的拼音,给出字符候选列表。 2.用户阅读完候选列表后从中选择词语“你好” 3....
  • 本文介绍了MySQL数据库中默认字符编码的设置方法,如何设置与修改mysql默认编码,my.ini设置字符编码的教程,需要的朋友参考下。 本节重点: mysql基础配置之mysql的默认字符编码的设置(my.ini设置字符编码) ...
  • 十分钟搞清字符集和字符编码

    千次阅读 2016-08-30 17:30:15
    什么是字符编码 UTF-8和Unicode的关系 UTF-8编码简介 为什么会出现乱码 如何识别乱码的本来想要表达的文字 常见问题处理之Emoji 本文将简述字符集,字符编码的概念。以及在遭遇乱码时的一些常用诊断技巧 ...
  • 下面这段代码使用了字节按照指定编码获取字符串,可能很多人也使用它,其实呢这段代码是错误的,如果使用的时候感觉一切正常的话,那只能说你运气挺好。 private String inputStreamToString(InputStream i

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 558,558
精华内容 223,423
关键字:

关于字符编码正确的是