精华内容
下载资源
问答
  • 字符编码的概念(UTF-8、UTF-16UTF-32都是什么鬼)

    万次阅读 多人点赞 2017-11-30 17:11:56
    字符集为每个字符分配了一个唯一的编号,通过这个编号就能找到对应的字符。在编程过程中我们经常会使用字符,而使用字符的前提就是把字符放入内存中,毫无疑问,放入内存中的仅仅是字符的编号,而不是真正的字符实体...

    字符集为每个字符分配了一个唯一的编号,通过这个编号就能找到对应的字符。在编程过程中我们经常会使用字符,而使用字符的前提就是把字符放入内存中,毫无疑问,放入内存中的仅仅是字符的编号,而不是真正的字符实体。

     

    这就抛出了一个问题,如何才能将字符编号放入内存中呢?

     

    对于 ASCII 字符集,这很容易。ASCII 总共包含 128 个字符,用 7 个比特位(Bit)恰好能够存储,不过考虑到计算机一般把字节(Byte)作为基本单元,为了操作方便,我们不妨用一个字节(也就是 8 个比特位)来存储 ASCII。这样虽然浪费了一个比特位,但是读写效率提高了。

     

    但是对于 Unicode,问题就没有这么简单了。Unicode 目前已经包含了上百万的字符,位置靠前的字符用一个字节就能存储,位置靠后的字符用三个字节才能存储。我们可以为所有字符都分配三个字节的内存,也可以为编号小的字符分配一个字节或者两个字节的内存,而为编号大的字符分配三个字节的内存。

     

    这两种方案各有优缺点,请读者看下面的分析。

    字符集和字符编码不是一个概念,字符集定义了文字和二进制的对应关系,为字符分配了唯一的编号,而字符编码规定了如何将文字的编号存储到内存中。有的字符集在制定时就考虑到了编码的问题,是和编码结合在一起的;有的字符集只管制定字符的编号,至于怎么编码,是其他人的事情。

    方案1:为每个字符分配固定长度的内存

    一种方案是为每个字符分配固定长度的内存,并且这块内存要足够大,可以容纳下所有的字符编号。这种方案最简单,直接将字符编号放入内存中即可,不需要任何转换,并且以后在字符串中定位字符、修改字符都非常容易。

    字符串就是一串连续的字符序列,它们在内存中按次序挨着存放。在C语言中,字符串由双引号 " "包围起来。

    目前的 Unicode 已经收录了上百万的字符,至少需要三个字节才能容纳下所有的字符编号。假设字符串"A3中¥"的 Unicode 编码值(十六进制形式)分别是 2A、31、DA49、BB672C,那么它们在内存中的存储形式为:

     

    在几乎所有的字符集中,常用字符的编号往往比较小,罕见字符的编号往往比较大,包括 Unicode 在内。

     

    A和3是 ASCII 编码中的字符,Unicode 为了兼容 ASCII,在设计时刻意保留了原来 ASCII 中字符的编号,所以英文字母和阿拉伯数字在 Unicode 中的编号都非常小,用一个字节足以容纳。中是一个汉字,编号比较大,一般要用两个字节才能容纳。¥可以看做是一个极其少见,或者只有极少数地区才会使用到的字符,这样的字符编号往往比较大,有时候需要三个字节才能容纳。

    是人民币符号,是汉字文化的一部分,它和其它汉字一样,实际上是用两个字节存储的,不过这里我们为了演示,故意犯错地说它需要三个字节。

    上图中带灰色背景的字节是没有用到的字节,它们就是被浪费掉的一部分内存空间,这就是用固定长度的内存来存储字符编号的缺点:常用字符的编号都比较小,这种方案会浪费很多内存空间,对于以英文为主的国家,比如美国、加拿大、英国等,内存利用率甚至会低于 50%。

    方案2:为每个字符分配尽量少的内存

    既然上面的方案有缺点,那我们就来改进一下。改进的思路也很明确,就是把空闲的内存压缩掉,为每个字符分配尽量少的字节,例如,A和3分配一个字节足以,中分配两个字节足以,如下图所示:

    这样虽然没有了空闲字节,不浪费任何内存空间了,但是又出现新的问题了:如果我不告诉你,你怎么知道2A表示一个字符,而不是2A31或者2A31DA才表示一个字符呢?后面的字符也有类似的问题。

     

    对于第一种方案,每个字符占用的字节数是固定的,很容易区分各个字符;而这种方案,不同的字符占用的字节数不同,字符之间也没有特殊的标记,计算机是无法定位字符的。

     

    这种方案还需要改进,必须让不同的字符编码有不同的特征,并且字符处理程序也需要调整,要根据这些特征去识别不同的字符。

     

    要想让不同的字符编码有不同的特征,可以从两个方面下手:

    1) 一是从字符集本身下手,在设计字符集时,刻意让不同的字符编号有不同的特征。

     

    例如,对于编号较小的、用一个字节足以容纳的字符,我们就可以规定这个字符编号的最高位(Bit)必须是 0;对于编号较大的、要用两个字节存储的字符,我们就可以规定这个字符编号的高字节的最高位必须是 1,低字节的最高位必须是 0;对于编号更大的、需要三个字节存储的字符,我们就可以规定这个字符编号的所有字节的最高位都必须是 1。

     

    程序在定位字符时,从前往后依次扫描,如果发现当前字节的最高位是 0,那么就把这一个字节作为一个字符编号。如果发现当前字节的最高位是 1,那么就继续往后扫描,如果后续字节的最高位是 0,那么就把这两个字节作为一个字符编号;如果后续字节的最高位是 1,那么就把挨着的三个字节作为一个字符编号。

     

    这种方案的缺点很明显,它会导致字符集不连续,中间留出大量空白区域,这些空白区域不能定义任何字符。

     

    2) 二是从字符编号下手,可以设计一种转换方案,字符编号在存储之前先转换为有特征的、容易定位的编号,读取时再按照相反的过程转换成字符本来的编号。

     

    那么,转换后的编号要具备什么样的特征呢?其实也可以像上面一样,根据字节的最高位是 0 还是 1 来判断字符到底占用了几个字节。

     

    相比第一种方案,这种方案有缺点也有优点:

     

    • 缺点就是多了转换过程,字符在存储和读取时要经过转换,效率低;
    • 优点就是在制定字符集时不用考虑存储的问题,可以任意排布字符。

     

    Unicode 到底使用哪种编码方案

    Unicode 是一个独立的字符集,它并不是和编码绑定的,你可以采用第一种方案,为每个字符分配固定长度的内存,也可以采用第二种方案,为每个字符分配尽量少的内存。

     

    需要注意的是,Unicode 只是一个字符集,在制定的时候并没有考虑编码的问题,所以采用第二种方案时,就不能从字符集本身下手了,只能从字符编号下手,这样在存储和读取时都要进行适当的转换。

     

    Unicode 可以使用的编码有三种,分别是:

    • UFT-8:一种变长的编码方案,使用 1~6 个字节来存储;
    • UFT-32:一种固定长度的编码方案,不管字符编号大小,始终使用 4 个字节来存储;
    • UTF-16:介于 UTF-8 和 UTF-32 之间,使用 2 个或者 4 个字节来存储,长度既固定又可变。

     

    UTF 是 Unicode Transformation Format 的缩写,意思是“Unicode转换格式”,后面的数字表明至少使用多少个比特位(Bit)来存储字符。

    1) UTF-8

    UTF-8 的编码规则很简单:如果只有一个字节,那么最高的比特位为 0;如果有多个字节,那么第一个字节从最高位开始,连续有几个比特位的值为 1,就使用几个字节编码,剩下的字节均以 10 开头。

     

    具体的表现形式为:

    • 0xxxxxxx:单字节编码形式,这和 ASCII 编码完全一样,因此 UTF-8 是兼容 ASCII 的;
    • 110xxxxx 10xxxxxx:双字节编码形式;
    • 1110xxxx 10xxxxxx 10xxxxxx:三字节编码形式;
    • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码形式。

     

    xxx 就用来存储 Unicode 中的字符编号。

     

    下面是一些字符的编码实例(绿色部分表示本来的 Unicode 编号):

     

    字符Næ
    Unicode 编号(二进制)010011101110011000101110 11101100
    Unicode 编号(十六进制)4EE62E EC
    UTF-8 编码(二进制)0100111011000011 1010011011100010 10111011 10101100
    UTF-8 编码(十六进制)4EC3 A6E2 BB AC

    对于常用的字符,它的 Unicode 编号范围是 0 ~ FFFF,用 1~3 个字节足以存储,只有及其罕见,或者只有少数地区使用的字符才需要 4~6个字节存储。

    2) UTF-32

    UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 编号即可,不需要任何编码转换。浪费了空间,提高了效率。

    3) UTF-16

    UFT-16 比较奇葩,它使用 2 个或者 4 个字节来存储。

     

    对于 Unicode 编号范围在 0 ~ FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换,这跟 UTF-32 非常类似。

     

    对于 Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储,具体来说就是:将字符编号的所有比特位分成两部分,较高的一些比特位用一个值介于 D800~DBFF 之间的双字节存储,较低的一些比特位(剩下的比特位)用一个值介于 DC00~DFFF 之间的双字节存储。

     

    如果你不理解什么意思,请看下面的表格:

     

    Unicode 编号范围
    (十六进制)
    具体的 Unicode 编号
    (二进制)
    UTF-16 编码编码后的
    字节数
    0000 0000 ~ 0000 FFFFxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxx2
    0001 0000---0010 FFFFyyyy yyyy yyxx xxxx xxxx110110yy yyyyyyyy 110111xx xxxxxxxx4

     

    位于 D800~0xDFFF 之间的 Unicode 编码是特别为四字节的 UTF-16 编码预留的,所以不应该在这个范围内指定任何字符。如果你真的去查看 Unicode 字符集,会发现这个区间内确实没有收录任何字符。

     

     

    UTF-16 要求在制定 Unicode 字符集时必须考虑到编码问题,所以真正的 Unicode 字符集也不是随意编排字符的。

    总结

    只有 UTF-8 兼容 ASCII,UTF-32 和 UTF-16 都不兼容 ASCII,因为它们没有单字节编码。

     

    如果你希望查看完整的 Unicode 字符集,以及各种编码方式,请猛击:https://unicode-table.com/cn/

    虽然这个网站有时候无法访问,但它是最好的一个查看 Unicode 字符集的网站。

    GB2312、Shift-JIS 等国家(地区)字符集怎么编码

    GB2312、GBK、Shift-JIS 等特定国家的字符集都是在 ASCII 的基础上发展起来的,它们都兼容 ASCII,所以只能采用变长的编码方案:用一个字节存储 ASCII 字符,用多个字节存储本国字符。

     

    以 GB2312 为例,该字符集收录的字符较少,所以使用 1~2 个字节编码。

    • 对于 ASCII 字符,使用一个字节存储,并且该字节的最高位是 0;
    • 对于中国的字符,使用两个字节存储,并且规定每个字节的最高位都是 1。

     

     

    由于单字节和双字节的最高位不一样,所以很容易区分一个字符到底用了几个字节。

    宽字符和窄字符(多字节字符)

    有的编码方式采用 1~n 个字节存储,是变长的,例如 UTF-8、GB2312、GBK 等;如果一个字符使用了这种编码方式,我们就将它称为多字节字符,或者窄字符。

     

    有的编码方式是固定长度的,不管字符编号大小,始终采用 n 个字节存储,例如 UTF-32、UTF-16 等;如果一个字符使用了这种编码方式,我们就将它称为宽字符。

     

    Unicode 字符集可以使用窄字符的方式存储,也可以使用宽字符的方式存储;GB2312、GBK、Shift-JIS 等国家编码一般都使用窄字符的方式存储;ASCII 只有一个字节,无所谓窄字符和宽字符。

    展开全文
  • Unicode编码详解(四):UTF-16编码

    千次阅读 2020-12-31 18:45:47
    Unicode编码详解(四):UTF-16编码 若觉得本文写得还可以,请多多关注本人所作书籍《C++语法详解》电子工业出版社出版,网盘...UTF-16是变长编码方式,每个字符编码为2或4字节。 2、历史 UTF-16编码源于UCS-2,是Uni

    Unicode编码详解(四):UTF-16编码


    本文是对《C++语法详解》一书相关章节的增补,以增强读者对字符及字符类型的理解,因为《C++语法详解》引用的标准过于老旧。

    《C++语法详解》网盘地址:

    https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

    本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)


    注意:若对本文的专业术语不了解,请参阅本系列文章(一)和(二)

    一、UTF-16编码简介

    1、

    UTF-16是变长编码方式,每个字符编码为2或4字节。

    2、历史
    • UTF-16编码源于UCS-2,是Unicode最早的编码方式。
    • UCS-2编码仅覆盖了基本平面(即BMP,第0平面)中的码点,使用固定的两字节将字符编号(类似于Unicode中的码点值)直接映射为字符编码,中间未经过任何的编码算法转换。
    • 很明显,16位的二进制位(范围为0x0000 ~ 0xFFFF)无法表示Unicdoe引入的增补平面中的码点(平面1 ~ 16,码点范围为0x10000~0x10FFFF),为此,Unicode在UTF-16编码中使用“代理(代替)机制”来解决这个问题,代理机制使用4个字节来表示增补平面中的码点,从而使UTF-16成为一种变长编码方式。
    • 因此,若软件仅支持UCS-2编码,则意味着仅支持UCS字符集或Unicode字符集基本平面中的字符,而不支持增补平面中的字符。

    二、代理(代替)机制与UTF-16编码规则

    1、代理机制的基本思想

    代理可简单理解为代替,其基本思想就是使用两个基本平面中未定义(或未使用)的码点合起来代替一个增补平面的码点。

    2、代理机制的基本规则
    • 基本平面中的字符(除U+D800~U+DFFF外)仍然使用固字两字节直接映射的方式编码,即,基本平面字符的字符编号(码点值)就是字符编码。
    • 增补平面的字符使用“代理机制”这一编码算法进行编码,使用代理机制后需要使用4字节来表示Unicode增补平面中的码点,因此,UTF-16也是一种变长编码方式。
    3、代理对和代理区
    • 代理对是指基本平面中用来代替增补平面码点的两个码点,也就是说,代理对是一对(即,两个)码点值。

    • 代理区

      • 基本平面中用来代替增补平面码点的未使用的码点区域被称为代理区,其码点范围为0xD800 ~ 0xDFFF,共2048个码点,
      • 代理区又分为高代理码点(或称为高代理码元,范围为0xD800 ~ 0xDBFF)和低代理码点(或称为低代理码元,范围为0xDC00 ~ 0xDFFF),图3为代理区的分类。
      • 需要注意的是,代理区中的码点都未定义字符,这些码点主要用于代理增补平面中的码点。假设为代理区中的码点指定了字符,那么一个代理区中的码元,到底是表示基本平面的字符呢还是增补平面中的字符的代理码元呢?这就产生了冲突,所以,为避免冲突,代理区中的码点都未定义字符。
        在这里插入图片描述
    4、UTF-16编码规则

    把高代理码点和低代理码点合起来组成“代理对”,使用代理对来代替增补平面的码点,代理对刚好可完全表示增补平面内的所有码点(原因见后文)。比如,增补平面的第一个码点0x10000的UTF-16编码是0xD800 DC00,同理,第二个码点0x10001的UTF-16编码是0xD800 DC01,其余以此类推。

    三、UTF-16编码方法

    1、方法1:查表

    根据UTF-16的编码规则可制出如表6所示的一个表格,然后通过查表的方式查找增补字符的编码,但这种方法非常麻烦,实际编码时并不使用。
    在这里插入图片描述

    2、方法2:计算法

    ①、将增补字符的码点值减去0x10000,得到一个20位长的二进制数

    ②、将得到的20位长二进制数拆分为高10位比特和低10位比特

    ③、20位长的高10位比特加上0xD800得到第一个代理码点,即高代理码点

    ④、20位长的低10位比特加上0xDC00得到第二个代理码点,即低代理码点

    ⑤、将得到的高代理码点和低代理码点组合成“代理对”,便得到了增补字符的UTF-16编码

    ⑥、示例:求增补平面码点值为U+10437的UTF-16编码

    • 将0x10437减去0x10000,得到0x00437,二进制为0000 0000 0100 0011 0111

    • 将高10位,即0000 0000 01加上0xD800(二进制为1101 1000 0000 0000),得到高代理码点为:0xD801(二进制为1101 1000 0000 0001)

    • 将低10位,即00 0011 0111加上0xDC00(二进制为1101 1100 0000 0000),得到低代理码点为:0xDC37(二进制为1101 1100 0011 0111)

    • 将高代理码点和低代理码点组合成代理对得到UTF-16编码为0xD801 DC37

    3、方法3:二进制位填补法

    ①、原理

    高代理码点的起始值0xD800(二进制为1101 1000 0000 0000)和低代理码点的起始值0xDC00(二进制为1101 1100 0000 0000),可发现,他们的前6位分别为110110和110111,而后10位都是0,总共有20位(220=1048576),刚好可表示增补平面中的所有码点(0x10000 ~ 0x10FFFF,共220=1048576个码点),若利用代理码点的这20位来表示增补码点,则高代理码点的范围为1101 1000 0000 0000(0xD800) ~ 1101 1011 1111 1111(0xDBFF),低代理码点的范围为1101 1100 0000 0000(0xDC00) ~ 1101 1111 1111 1111(0xDFFF),刚好在高代理码点和低代理码点的范围内。因此,可利用填补二进制位的方法来编码UTF-16

    ②、步骤1:

    将高代理码点和低代理码点分别展开为如图4所示的形式,其中高代理单元的110110和低代理单元的110111是固定不变的数(定数),p和x是变数,去掉定数后组合起来就是pppp xxxx xxxx xxxx xxxx,共20位,刚好可表示全部增补码点,其中pppp表示16个增补平面的编码(24=16),紧接着的16个x表示某个增补平面内的码点。
    在这里插入图片描述
    ③、步骤2、

    将增补字符的码点值减去0x10000,得到一个20位长的二进制数

    ④、步骤3、

    将得到的20位长二进制数依次填补步骤1中的变数便得到UTF-16的编码

    ⑤、示例:

    求增补平面码点值为U+10437的UTF-16编码

    • 将0x10437减去0x10000,得到0x00437,二进制为0000 0000 0100 0011 0111
    • 将0000 0000 0100 0011 0111依次填补高代理单元和低代理单元中的变数(如图5所示),得到其编码为0xD801
      DC37
      在这里插入图片描述

    四、字节序问题

    UTF-16编码后的码元序列在映射为物理意义上的字节序列时,又分为UTF-16BE (大端序),UTF-16LE (小端序)两种情况,大端序和小端序又分为带有字节序标记(with BOM)和不带字节序标记(without BOM)两种情形。比如,“ABC”这三个字符的UTF-16编码(码元序列)为:00 41 00 42 00 43;其对应的各种字节序列如表7所示:
    在这里插入图片描述

    五、在记事本中使用UTF-16编码

    在这里插入图片描述
    在这里插入图片描述

    六、UTF-16编码的优缺点及特点

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    九、Unicode编码方式总结

    在这里插入图片描述
    代码页、内码、外码、汉字编码简介

    本文作者:黄邦勇帅(原名:黄勇)
    在这里插入图片描述

    展开全文
  • 前言:上一篇文章写了关于Unicode,以及utf-8、utf-16相关知识。所以本篇博文来验证在java环境下,字符在不同编码下所占的字计数。 测试代码如下:package string;public class CharByteTest { public static void ...

    前言:上一篇文章写了关于Unicode,以及utf-8、utf-16相关知识。所以本篇博文来验证在java环境下,字符在不同编码下所占的字计数。

    测试代码如下:

    package string;
    
    public class CharByteTest {
    
        public static void main(String[] args) throws Exception {
            // 第二个字符为BMP之外的字符,csdn编辑器无法显示该字符,可以在运行结果截图中看到
            String[] strArr = {"中", "��", "a", "aa"};
            String[] charsetArr = {"gbk", "utf-8", "utf-16", "gb2312"};
            for(String str : strArr) {
                System.out.println(str);
                for(String charset : charsetArr) {
                    byteTest(str, charset);
                }
                System.out.println("============================");
            }
        }
    
        public static void byteTest(String str, String charset) throws Exception {
            System.out.println("编码:" + charset 
                    + "\t所占字节数:" + str.getBytes(charset).length);
        }
    
    }

    运行结果如下:

    这里写图片描述

    在前一篇文章的基础上,我们来分析一下运行结果。

    1. “中”字的unicode码值为4E2D,使用UTF-8编码占3个字节。由于该字符位于BMP内,所以使用UTF-16编码应该占2个字节,但是运行结果为4个字节。
    2. 第二个字符(csdn编辑器不支持该字符的显示),该字符使用UTF-8应该占4个字节,运行结果正确。由于该字符位于BMP外,所以使用UTF-16编码应该占4个自己,但是运行结果显示占用了6个字节。
    3. 英文字母a,UTF-8编码应该和ASCII编码相同占用一个字节,运行结果显示占用一个字节。a在Unicode中位于BMP内,所以UTF-16编码应该占用4个字节,但是运行结果缺显示4个字节。
    4. 按照上面的运行结果,a在UTF-8编码下占用1个字节,在UTF-16编码下占用4个字节。那么猜测两个英文字母a,即”aa“在UTF-8和UTF-16编码下应该分别占2个和8个字节,但是运行结果却和想象中的不一样,aa在UTF-16编码下工占6个字节。

    运行结果好像和上一篇中讲到的有点不相符啊!为什么会出现这样的结果的?

    通过搜索相关文章,了解到java的字节码文件(.class)文件采用的是UTF-8编码,但是在java 运行时会使用UTF-16编码。在转码的时候会在前面加上表示字节顺序的字符,这个字符称为”零宽度非换行空格”(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。FEFF占用两个字节,所以就解释了为什么java环境下英文字母a在UTF-16编码占3个字节。

    我们不妨将这些字符的在不同编码下的二进制转换为16进制并打印出来。
    将代码修改如下:

    package string;
    
    public class CharByteTest {
    
        private static char[] HEX_CHAR = {'0', '1', '2', '3', '4',
                '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    
        public static void main(String[] args) throws Exception {
    
            String[] strArr = {"中", "��", "a", "aa"};
            //String[] charsetArr = {"gbk", "utf-8", "utf-16", "gb2312"};
            String[] charsetArr = {"unicode", "utf-8", "utf-16", "utf-16BE", "utf-16LE"};
            for(String str : strArr) {
                System.out.println(str);
                for(String charset : charsetArr) {
                    byteTest(str, charset);
                }
                System.out.println("============================");
            }
        }
    
        public static void byteTest(String str, String charset) throws Exception {
            byte[] strByte = str.getBytes(charset);
            System.out.println("编码:" + charset 
                    + "\t所占字节数:" + strByte.length
                    + "\t16进制:" + bytesToHexStr(strByte));
        }
    
        // 将byte[]用十六进制字符串
        public static String bytesToHexStr(byte[] bytes) {
            int index = 0;
            char[] hexChar = new char[bytes.length * 2];
            for(int i = 0; i < bytes.length; i++) {
                hexChar[index++] = HEX_CHAR[bytes[i] >> 4 & 0xF];
                hexChar[index++] = HEX_CHAR[bytes[i] & 0xF];
            }
            return new String(hexChar);
        }
    
    }

    运行结果:
    这里写图片描述

    展开全文
  • c语言gbk、utf8转换编码表及函数

    热门讨论 2013-08-28 08:51:52
    c语言的gbk和unicode的编码对照表以及gbk和utf8的相互转换函数(比较全)。
  • 一些设备串口通讯使用的是unicode,这时候我们解码就要使用unicode 编码包含的是中文,英文,俄文还是日文什么的,只要把它转换成Unicode就能被识别,而不用再考虑...unicode编码UTF8)的十六进制 与字符 互相转换
  • Qt 字符编码转换(UTF-8 转换为 GBK)

    万次阅读 2018-08-13 15:26:35
    很多时候可能需要字符编码的转换,最近我需要获取一段字符串的长度,我strlen() 获取的’你好’ 的字节长度为6 ,我记得每个汉字占用2字节 ,查了一下 UTF-8格式 汉字(含繁体)占3字节,需要下码. 编码知识 ...

    字符串编码格式转换

    很多时候可能需要字符串编码的转换,最近我需要获取一段字符串的长度,我strlen() 获取的’你好’ 的字节长度为6 ,我记得每个汉字占用2字节 ,查了一下 UTF-8格式 汉字(含繁体)占3字节,需要转下码.

    编码知识

    Qt常见的两种编码是:UTF-8和GBK
    UTF-8Unicode TransformationFormat-8bit,允许含BOM,但通常不含BOM。是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24为(三个字节)来编码。UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。UTF-8编码的文字可以在各国支持UTF8字符集的浏览器上显示。如,如果是UTF8编码,则在外国人的英文IE上也能显示中文,他们无需下载IE的中文语言支持包。
    
    GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示,为了区分中文,将其最高位都设定成1。GBK包含全部中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBD大。GBK是GB2312的扩展,除了兼容GB2312外,它还能显示繁体中文,还有日文的假名。
    
    GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:
    GBK、GB2312--Unicode--UTF8
    UTF8--Unicode--GBK、GB2312 
    在简体中文windows系统下,ANSI编码代表GBK/GB2312编码,ANSI通常使用0x80~0xFF范围的2个字节来表示1个中文字符。0x00~0x7F之间的字符,依旧是1个字节代表1个字符。Unicode(UTF-16)编码则所有字符都用2个字节表示。

    上面说了 GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换 但是我试了下 utf-8 可以直接转换为 gbk

    Qt中 提供了 一个字符串转码的类 QTextCodec

    The QTextCodec class provides conversions between text encodings.
    Qt uses Unicode to store, draw and manipulate strings. In many situations you may wish to deal with data that uses a different encoding. For example, most Japanese documents are still stored in Shift-JIS or ISO 2022-JP, while Russian users often have their documents in KOI8-R or Windows-1251.
    Qt provides a set of QTextCodec classes to help with converting non-Unicode formats to and from Unicode. You can also create your own codec classes.
    The supported encodings are:
    Big5
    Big5-HKSCS
    CP949
    EUC-JP
    EUC-KR
    GB18030
    HP-ROMAN8
    IBM 850
    IBM 866
    IBM 874
    ISO 2022-JP
    ISO 8859-1 to 10
    ISO 8859-13 to 16
    Iscii-Bng, Dev, Gjr, Knd, Mlm, Ori, Pnj, Tlg, and Tml
    KOI8-R
    KOI8-U
    Macintosh
    Shift-JIS
    TIS-620
    TSCII
    UTF-8
    UTF-16
    UTF-16BE
    UTF-16LE
    UTF-32
    UTF-32BE
    UTF-32LE
    Windows-1250 to 1258
    译文:
    QTextCodec类提供文本编码之间的转换。
    Qt使用Unicode存储、绘制和操作字符串。在许多情况下,您可能希望处理使用不同编码的数据。例如,大多数日本文档仍然存储在Shift-JIS或ISO 2022-JP格式,而俄罗斯用户的文档通常存储在KOI8-R或windows 1251格式。
    Qt提供了一组QTextCodec类,以帮助将非Unicode格式转换为Unicode格式。您还可以创建自己的编解码器类。
    支持的编码是:
    Big5
    Big5-HKSCS
    CP949
    EUC-JP
    EUC-KR
    GB18030
    HP-ROMAN8
    IBM 850
    IBM 866
    IBM 874
    ISO 2022-JP
    ISO 8859-1 to 10
    ISO 8859-13 to 16
    Iscii-Bng, Dev, Gjr, Knd, Mlm, Ori, Pnj, Tlg, and Tml
    KOI8-R
    KOI8-U
    Macintosh
    Shift-JIS
    TIS-620
    TSCII
    UTF-8
    UTF-16
    UTF-16BE
    UTF-16LE
    UTF-32
    UTF-32BE
    UTF-32LE
    Windows-1250 to 1258

    我用到的就很简单 utf-8 转为 gbk
    如果你原本编码不是 utf-8 就要先转换 utf-8 这里我们假设 原本编码也不是utf-8

    #include <QTextCodec>
    
        QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");  
    
        QTextCodec::setCodecForLocale(utf8);
    
        QTextCodec* gbk = QTextCodec::codecForName("gbk");
    
        QString str1="您好";
    
        //utf8 -> gbk
    
        //1. utf8 -> unicode
    
        QString strUnicode= utf8->toUnicode(str1.toLocal8Bit().data());
    
        //2. unicode -> gbk, 得到QByteArray
    
        QByteArray gb_bytes= gbk->fromUnicode(strUnicode);
    
    
        //gbk -> utf8
    
        //1. gbk to unicode
        strUnicode=gbk->toUnicode(str1.toLocal8Bit().data());
        //2. unicode -> utf-8
        QByteArray utf8_bytes=utf8->fromUnicode(strUnicode);
    
    

    格式转换为 gbk 以后 汉字就是2字节了,搞定

            -来自98年菜鸡一枚,请大佬们多多关照!
    
    展开全文
  • 本文用于介绍不同编码格式的string(char*)之间的转换。...由于UTF-8使用广泛,以utf-8编码为例,介绍其与其它编码方式的流程。 UTF-8 广义的Unicode的一个标准,定义了一个字符集以及一系列的编码规则,即 Unicode
  • 最近使用到了mysql-connector-cpp,通过这个库获取到的字符串类型是mysql::string,其实其实质就是mysql自己实现的wstring。 如果直接进行转换: ...所以我们必须先将utf-16字符串转化为utf-8的字符串。...
  • JS中文字符串和UTF-8编码字符串相互转换1.中文字符串转化为UTF-8编码,如“<汉字>”的UTF-8编码为“%3C%E6%B1%89%E5%AD%97%3E” 2.UTF-8编码字符串“%E6%B1%89%E5%AD%97”的中文为“<汉字>”function EncodeUtf8(s1...
  • 字符串转换成UTF8编码

    千次阅读 2016-10-19 10:19:00
    在使用网络GET请求时,一般要先将url中的汉字进行encode成UTF8格式的编码,否则在使用时可能报告网址不存在的错误,这时就需要进行转换。
  • 字符编码之间的相互转换 UTF8与GBK

    千次阅读 2018-08-12 12:33:00
    UTF8与GBK字符编码之间的相互转换 C++ UTF8编码转换 CChineseCode 一 预备知识 1,字符字符是抽象的最小文
  • lua中怎么从utf16转utf8 ? 从网上找到个js的实现方法,但是不知道参数是什么, ``` function utf16ToUtf8(s){ if(!s){ return; } var i, code, ret = [], len = s.length; for(i = 0; i ; i++){ ...
  • UTF-16编码详解

    千次阅读 2017-02-21 17:29:08
    关于UTF-16的设计思路和设计原理
  • golang:字符编码转换(UTF8与GBK)

    千次阅读 2019-11-24 14:49:55
    UTF8与GBK字符编码转换: package main import ( "bytes" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" "io/ioutil" "log" "os" ) func main() { { // GBK TO...
  • string字符转UTF-16 function ToUTF16(str) { var result = new Array(); var k = 0; for (var i = 0; i < str.length; i++) { var j = str[i].charCodeAt(0); result[k++] = j >> 8; result[k++] ...
  • golang 字符编码转换 gbk转utf8

    万次阅读 2018-02-08 11:21:03
    需要调取一个第三方的接口,接口返回的内容的编码格式是gbk的,但是golang内建只认utf8,所以需要将gbk的字符串转换为utf8,才能进行后续的数据处理。 问题处理: 引入开源包 go get github.com/axgle/mahonia 此...
  • 字符串的编码格式转换为utf-8

    千次阅读 2018-12-08 19:17:00
    * 将字符串的编码格式转换为utf-8 * * @param str * @return Name = new * String(Name.getBytes("ISO-8859-1"), "utf-8"); */ public static String toUTF8(String str) { if (isEmpty(str)) { ret...
  • JS字符串中文转UTF编码

    千次阅读 2019-03-22 07:23:02
    function _uniencode(str){ str = str || '' var newStr = '' for (var i = 0,len = str.length;i ; i++ ) { console.log(str[i]) console.log(str[i]....实现字符串中code大于256的用UTF转码功能。 复制代码
  • 1、多字节编码字符转UTF8字符编码
  • Python3中普通ASCII编码字符串没有decode()方法,UTF-8编码的字符串有decode()方法 举例如下 普通字符串没有decode ( ) 方法 ch = '\xe5\xa5\xbd' print ( ch ) 结果:好 (按ASCII字符打印) UTF - 8 ...
  • C++中字符编码的转换(Unicode、UTF-8、ANSI)

    万次阅读 多人点赞 2018-09-25 14:11:09
    C++的项目,字符编码是一个大坑,不同平台之间的编码往往不一样,如果不同编码格式用一套字符读取格式读取就会出现乱码。因此,一般都是转化成UTF-8这种平台通用,且支持性很好的编码格式。 Unicode、UTF-8的概念不...
  • 好容易写好了驱动,GET 了一下天气网站的 API 返回竟然是中文乱码,猜测是 UTF8 乱码,果不其然.于是就自己去寻找网上大神们的解决方案:一般是 UTF-8 -&gt; Unicode -&gt;GBK (中文) 关键字: stm32103 嵌入式 ...
  • 文章目录前言简述ASCIIGBKUnicodeUTF-8应用场景开发环境编码转换16进制数值转换为16进制字符16进制数值转化为字符串16进制字符串转换为Unicode字符串Unicode字符串转化为16进制字符串总结参考资料 前言 字符编码方式...
  • UTF-8、UTF-16UTF-32编码的相互转换

    千次阅读 2014-02-23 21:37:34
    最近在考虑写一个可以跨平台的通用字符串类,首先需要搞定的就是编码转换问题。 vs默认保存代码文件,使用的是本地code(中文即GBK,日文即...因此不论在哪种系统里,程序在处理字符串时都需要考虑UTF编码之间的相互
  • utf8与utf16转换

    千次阅读 2019-03-14 23:18:59
    1.UTF8与UTF16编码转换 std::string ConvertFromUtf16ToUtf8(const std::wstring&amp; wstr) { std::string convertedString; int requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, 0, 0, 0...
  • 踩过的坑1:怎么把存储UTF-8编码字符串转换成实际字符首先说明下问题。之前用爬虫从网上down数据的时候因为没有思考到位,结果出现了一个很奇葩的问题。一般来说中文采用UTF8编码后写成byte[]的格式然后存储在...
  • 1. 使用Word文档能够实现 字符串和utf8编码的转换。 快捷键是 ALT+X 在知乎的一个里面看到一个说法: ㍾ ㍽ ㍼ ㍻ - 这四个在Unicode表里是倒序排列的,而且只预留了这四个年号,㍻ 之后的u+337f,是 ㍿ ,㍾ ...
  • 字符转utf8编码

    千次阅读 2017-06-02 10:56:39
    url字符串中存在中文,需要把中文转换成utf8编码,我所知道的四种方法: Uri.EscapeUriString ,Uri.EscapeDataString ,HttpUtility.UrlEncode,WWW.EscapeURL:  HttpUtility.UrlEncode存在System.Web中,需要在...
  • 自:https://blog.csdn.net/dongchongyang/article/details/52484794ANSI和ASCII区别ANSI码(American National Standards Institute)美国国家标准学会的标准码ASCII码(America Standard Code for Information ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 471,697
精华内容 188,678
关键字:

utf16编码转字符