各种编码UNICODE、UTF-8、ANSI、ASCII、GB2312、GBK详解

操作系统 计算机网络 算法 架构

Ascii编码
开始计算机只在美国用。八位的字节一共可以组合出256(0xFF)种不同的状态;
于是最开始只有一个标准 美国信息互换标准代码(即Ascii编码 American Standard Code for Information Interchange);
Ascii只用了0x00-0x7F(0-127),才127位,剩下的0x7F之后就空出来了;
signed char取值范围-128 到 127(有符号位) 刚好也是到127 巧合网络图片侵删
(网络图片侵删)

扩展字符集
等到其他国家开始用计算机之后,剩下的127位之后就用来保存他们的文字。
从128到255这一页的字符集被称”扩展字符集”;

GB2312
这是其他国家的处理,中国怎么处理呢?
我们采用单字节双字节混合的方式编排字符集:
一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字;
前面的一个字节(高字节)从 0xA1 到 0xF7
后面的一个字节(低字节)从 0xA1 到 0xFE
这样我们就可以组合出大约7000多个简体汉字了。
从这里开始我们就使用了双字节表示汉字了
连在 ASCII 里本来就有的数字 标点 字母都统统重新以两个字节长的方式编进来,
这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了
这种汉字方案叫做 “GB2312”。GB2312 是对 ASCII 的中文扩展。

GBK标准
慢慢的发现7000多个简体汉字还是不够,还有一些罕见汉字,繁体字,符号无法表达,继续扩展
干脆不再要求低字节一定是127号之后的内码,
只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容
扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312 的所有内容,
同时又增加了近20000个新的汉字(包括繁体字)和符号。

少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK 扩成了 GB18030

ANSI
新建一个文本文件时,记事本的编码默认是ANSI, 如果你在ANSI的编码输入汉字,那么他实际就是GB系列的编码方式
在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码

UNICODE
各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码
国际标谁化组织(ISO)决定着手解决这个问题:UNICODE 开始制订
ISO 就直接规定
1 用两个字节(也就是16位)来统一表示所有的字符
2 UNICODE 保持Ascii制定的原编码不变只是将其长度由原来的8位补充0x00后扩展为16位
3 其他文化和语言的字符则全部重新统一使用两个字节重新编码
UNICODE 是用两个字节来表示为一个字符,他总共可以组合出65535不同的字符
这大概已经可以覆盖世界上所有文化的符号

UTF-8
Unicode转换格式(UTF=UnicodeTransformationFormat)
计算机网络的兴起 UNICODE 如何在网络上传输也是一个必须考虑的问题
UTF8就是每次8个位传输数据,而UTF16就是每次16个位
只不过为了传输时的可靠性,从UNICODE到UTF时并不是直接的对应,而是要过一些算法和规则来转换
一些计算机是采用低位先发送的方法,例如我们PC机采用的 INTEL 架构
而另一些是采用高位先发送的方式
在文本流的开始时向对方发送一个标志符
如果之后的文本是高位在前就发送”FEFF”,低位在前则发送”FFFE”
utf-8来说利于传输因为它是变长的,有一个字节的(ascii在utf-8中都只占一个字节并且是一致的),俩的,三个的。
有一个传输出错不会影响其他的。
如果是固定长度的多字节编码,少一个字节后面的往前补上,所有的字符编码都变了,都成乱码了。
而utf-8字符编码的每个字节都不会是0000h

Unicode和UTF-8的关系
Unicode使用了2个字节来表示一个字符 大大增加传输带宽和存储空间 所以如何处理这个问题
Unicode只是一个符号集,本身没有能力处理这个问题
它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储 采取哪种编码方式存储
甚至到后来的互联网的普及,强烈要求出现一种统一的编码方式
UTF-8就是在互联网上使用最广的一种unicode的实现方式
其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。
重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。
它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度
UTF-8的编码规则很简单,只有二条
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10

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是4E25(100111000100101)
使用UTF-8进行编码时需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”
11100100 10111000 10100101

以上内容主要转载 http://blog.csdn.net/lvxiangan/article/details/8151670

字符串文本比较

// main.cpp(UTF-8)
#include <stdio.h>
#include <string.h>

int main(){
    FILE* fp;
    fp = fopen("test.txt", "r");

    fseek(fp, 0, SEEK_END);  
    int size = ftell(fp); 
    rewind(fp);  
    printf("file size = %d\n", size);
    char buf[1024] = {0};
    fread(buf, sizeof(char), size, fp);
    fclose(fp);
    printf("test.txt >>> %s\n", buf);
    for(int i=0; i<size; i++){
        printf("%02x ", (unsigned char)buf[i]);
    }
    printf("\n");

    char* str = (char*)"中文";
    int i = 0;
    while(str[i]!='\0'){
        printf("%02x ", (unsigned char)str[i]);
        i++;
    }
    printf("\n");
    printf("%7s : %d\n", "==", buf == str);
    printf("%7s : %d\n", "strcmp", strcmp(buf, str));
    printf("%7s : %d\n", "strncmp", strncmp(buf, str, size));
    return 0;
}

运行结果:

$ ./a.out       
file size = 6
test.txt >>> 中文
e4 b8 ad e6 96 87 
e4 b8 ad e6 96 87 
     == : 0
 strcmp : 0
strncmp : 0

test.txt(UTF-8)文件 只有两个中文字符 : “中文”
在UTF-8编码中 “中文”= e4 b8 ad e6 96 87

这里使用printf输出过程中一定要使用unsigned char进行输出,否则超出127的会使用补码形式输出

strcmp源码 :

int strcmp(const char *str1,const char *str2)
{
    while(*str1 == *str2)
    {
        if(*str1 == '\0')
            return0;

        str1++;
        str2++;
    }
    return *str1 - *str2;
}

根据strcmp源码来看,尝试修改我的CPP文件的编码格式main.cpp(UTF-8)>>>main.cpp(ANSI).text.txt保持格式不变
此时,我的main.cpp里面出现的字符包括“中文”都以ANSI的编码格式出现 ANSI编码的“中文”=”d6 d0 ce c4”

$ ./a.out 
file size = 6
test.txt >>> 中文
e4 b8 ad e6 96 87 
strlen = 6
d6 d0 ce c4 
     == : 0
 strcmp : 14
strncmp : 14

在使用main.cpp(Unicode)时发生报错的情况, 可以看出gcc对于不同文件编码的支持仍然有限制!
main.cpp:1: error: stray ‘\377’ in program
main.cpp:1: error: stray ‘\376’ in program
main.cpp:1: error: stray ‘#’ in program
main.cpp:1: warning: null character(s) ignored
main.cpp:1: warning: null character(s) ignored

我的Ubuntu下 gcc能编译通过的文件编码有:UTF-8、 ANSI

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值