精华内容
下载资源
问答
  • 压缩原理及步骤&&压缩比的计算压缩原理及步骤压缩的第一步: 将一个文件以各个字符出现...这个特性保证了即使我们把不同长度的编码存在一起,仍然也可以把它们分离开,不会出现认错人的冲突。 那么我们就可以把所有

    压缩原理及步骤&&压缩比的计算

    压缩原理及步骤

    压缩的第一步:

    将一个文件以各个字符出现的次数为权值建立哈夫曼树,这样每个字符可以用从树根到该字符所在到叶子节点的路径来表示。(左为0,右为1)

    压缩第二步:

    哈夫曼编码有一个很重要的特性:每个字符编码不会成为另一个编码的前缀。这个特性保证了即使我们把不同长度的编码存在一起,仍然也可以把它们分离开,不会出现认错人的冲突。
    那么我们就可以把所有的字符按照原有顺序用其编码替换,构建新的字符串作为其压缩后的串。

    压缩第三步:

    有的小伙伴可能要问了,这样一搞不是越变越多了么,哪是什么压缩。哈哈,大部分孩子可能已经想到啦,既然单位编码除了0就是1为什么还要用字节来存呢,用位来保存,8个单位编码为1位。这样转化完成后的串才是真正压缩后的串。

    当然,因为我们还要进行解压,所以这里构建的树也要和串一并加入到文件。

    压缩比的计算

    介绍完步骤,我们来计算一下哈夫曼编码的压缩比。 用len表示串长度,path(i)表示每i个字符的编码长度,那么根据上文所介绍的原理,我们可以很容易知道,串通过哈夫曼压缩后的长度为
    sum(path(i)) 1<=i<=len
    这个式子虽然正确但不能直观的感受的压缩比,所以我们来假设一种平均情况进行估算 假如一个 串长度为n,一共包含 m个不同的字符,那么所构建成的哈夫曼树的 总结点数为 2*m-1。 假设,n很大,那么可以忽略树的保存所占用的空间。如果假设此串中每个字符出现的次数都是相同的,那么也可以假设,它们所生成的哈夫曼树是完全二叉树. 即每个叶子(字符)的 深度为log(m)+1,则路径长度为log(m)。log(m)即为该串字符的平均路径长度,那么压缩后的串长为log(m)/8。 由上可以得出平均压缩比的公式为:
    n*log(2*m-1)/8/n = log(2*m-1)/8;
    可见压缩比的大小主要与m有关,即不同的字符越少越好。 ascii码的范围为0~255,共有256种不同字符,代入上式得
    log(2*256-1) = 6.23 …
    向上取整为7(路径个数哪有小数)
    7/8 = 0.875 = %87.5
    所以哈夫曼编码的平均压缩比为%87.5。

    强调

    上述的假设在计算情况中忽略了对哈夫曼树的保存,所以只在文件总长度与不同字符总数相差很大时才生效。

    考虑ascii码外的其它语言

    一开始为考虑这个钻了牛角尖,想着去统一用wchar_t保存或是转为Unicode等等什么的。但其实不必那么复杂,因为汉字(不仅仅汉字,任何字符都是这样的)都是以字节为单位的,由多个字节组成的,将其分开对待,因为最终解压时恢复原串还是按照原有顺序组装,所以和纯英文文件的实现没有什么区别);

    需要注意的地方

    所有字符路径的总长不一定整除8,所以在按为保存时,要注意最后一项不足8的情况,进行补零,且要将补零的个数保存起来。

    代码对不同类型文档的压缩比测试情况

    英语文章

    样例文档:西游记英文节选

    原大小:7720
    压缩后:10476
    压缩比:1.356 – %135
    此处的文件压缩后不降反增,因为文件本身大小与不同字符的数量相差并不大,加上对树的保存后,空间大于压缩前。

    纯汉语文档

    样例文档:西游记
    原大小:1921978
    压缩后:1781234
    压缩比:0.926 – %92
    不同汉字的数量多。

    程序代码

    样例文档:github网页源代码
    原大小:46500
    压缩后:35116
    压缩比:0.755 – %76
    源代码中全是英文字母与符号,不超过100种,总大小与其相差近500倍,且代码重复词比较多。

    英语单词文档

    样例文档:英语单词5000
    原大小:20813
    压缩后:13523
    压缩比:0.649 – %65

    测试情况

    源代码

    压缩程序源文件 compress.cpp

    #include <iostream>
    #include <locale>
    #include <cstdlib>
    #include <fstream>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    const long long MAX_SIZE = 10000000000;//
    const int MAX_TYPE = 300;
    unsigned int *f = new unsigned int[MAX_TYPE];//计数
    unsigned int *p = new unsigned int[MAX_TYPE];//计下标
    char *v = new char[MAX_TYPE];
    char filename[20];
    char *s[MAX_TYPE];
    
    struct Node
    {
        unsigned int weight, parent, lson, rson;
        Node(){};
    }HuffmanTree[MAX_TYPE<<1];
    
    struct NodeCmp
    {
        bool operator()(int a, int b)
        {
            return HuffmanTree[a].weight > HuffmanTree[b].weight;
        }
    };
    
    int CreatTree(char *str, long long len)
    {
        int num = 1;
        for(int i=0;i<len;i++)
            f[str[i]]++;
        cout<<"len::"<<len<<endl;
        for(int i=0;i<len;i++)
        {
            if(f[str[i]])
            {
                HuffmanTree[num].weight = f[str[i]];
                HuffmanTree[num].lson = 0;
                HuffmanTree[num].rson = 0;
                f[str[i]] = 0;
                if(p[str[i]] == 0)
                    p[str[i]] = num;
                v[num] = str[i];
                ++num;
            }
        }
        cout<<"num::"<<num<<endl;
        return num;
    }
    
    void CodingTree(int num)
    {
        priority_queue<int, vector<int>, NodeCmp> q;
        for(int i=1;i<num;i++)
            q.push(i);
        int len = num;
        for(int i=0;i<num-2;i++)
        {
            int x = q.top(); q.pop();
            int y = q.top(); q.pop();
            HuffmanTree[len].weight = HuffmanTree[x].weight + HuffmanTree[y].weight;
            HuffmanTree[x].parent = HuffmanTree[y].parent = len;
            HuffmanTree[len].lson = y;
            HuffmanTree[len].rson = x;
            q.push(len++);
        }
    }
    
    void FindPath(int num)
    {
        char *t = new char[num];
        t[num-1] = '\0';
        for(int i=1;i<num;i++)
        {
            int son = i, father = HuffmanTree[i].parent;
            int start = num-1;
    
            while(father != 0)
            {
                --start;
                if(HuffmanTree[father].rson == son)
                    t[start] = '1';
                else
                    t[start] = '0';
                son = father;
                father = HuffmanTree[father].parent;
            }
            s[i] = new char[num - start];
            strcpy(s[i], &t[start]);
        }
    }
    
    void print(int num, long long len, char *str)
    {
        ofstream fout(filename, ios::out);
        fout<<num<<endl;
        for(int i=1;i<num;i++)
        {
            fout<<s[i]<<endl;
            fout<<v[i]<<endl;
        }
        long long pos = 0;
        char *ans = new char[MAX_SIZE];
    
        int now = 7;
        for(long long i=0;i<len;i++)
        {
            int k = 0;
            while(s[p[str[i]]][k] != '\0')
            {
                ans[pos] |= (s[p[str[i]]][k]-'0')<<now--;
                if(now < 0)
                {
                    now = 7;
                    pos++;
                }
                ++k;
            }
        }
    
        int zero = 0;
        if(now != 7) zero = now%7+1, pos++;
    
        fout<<zero<<" "<<pos<<endl;
        fout.write(ans, sizeof(char)*pos);
        fout.close();
    
        cout<<"zero::"<<zero<<endl;
    }
    
    int main(int argc, char **argv)
    {
        sprintf(filename, "%s.temp", argv[1]);
        ifstream fin(argv[1],ios::ate | ios::in);
        if(!fin)
        {
            cout<<"File open error!"<<endl;
            return 0;
        }
    
        long long size = fin.tellg();
        if(size > MAX_SIZE)
        {
            cout<<"Too long!"<<endl;
            return 0;
        }
        fin.seekg(0, ios::beg);
    
        char *str = new char[size+1];
        fin.read(str,size);
        fin.close();
    
    
        int num = CreatTree(str, size);
        CodingTree(num);
        FindPath(num);
        print(num, size, str);
    
        return 0;
    }

    解压程序源文件 compress.cpp

    #include <iostream>
    #include <locale>
    #include <cstdlib>
    #include <fstream>
    #include <vector>
    #include <queue>
    
    using namespace std;
    char filename[20];
    const long long MAX_SIZE = 10000000000;//
    const int MAX_TYPE = 300;
    struct Node
    {
        char v;
        int parent, lson, rson;
        Node(){};
    }HuffmanTree[MAX_TYPE<<1];
    
    char *str = new char[MAX_SIZE];
    char *ans = new char[MAX_SIZE];
    
    void CreatTree(char *t, char v, int &pos)
    {
        int root = 0;
        for(int i=0;t[i]!='\0';i++)
        {
            if(t[i] == '1')
            {
                if(HuffmanTree[root].rson == 0)
                    HuffmanTree[root].rson = pos++;
                root = HuffmanTree[root].rson;
            }
            else
            {
                if(HuffmanTree[root].lson == 0)
                    HuffmanTree[root].lson = pos++;
                root = HuffmanTree[root].lson;
            }
        }
        HuffmanTree[root].v = v;
    }
    
    void print(int zero, int len, char *str)
    {
        long long start = 0;
        int root = 0;
        int end = 0;
        for(int i=0;i<len;i++)
        {
            char t = str[i];
            if(i == len-1)
                end = zero;
            for(int j=7;j>=end;j--)
            {
                if((1<<j) & t)
                    root = HuffmanTree[root].rson;
                else
                    root = HuffmanTree[root].lson;
                if(HuffmanTree[root].lson == 0 && HuffmanTree[root].rson == 0)
                {
                    ans[start++] = HuffmanTree[root].v;
                    root = 0;
                }
            }
        }
        cout<<"len::"<<start<<endl;
        ofstream out(filename, ios::out);
        out.write(ans, sizeof(char)*(start));
        out.close();
    }
    
    int main(int argc, char **argv)
    {
        strcpy(filename, argv[1]);
        filename[strlen(filename)-4] = 'o';
        filename[strlen(filename)-3] = 'u';
        filename[strlen(filename)-2] = 't';
        filename[strlen(filename)-1] = '\0';
    
        ifstream fin(argv[1], ios::in);
        if(!fin)
        {
            cout<<"File open error!"<<endl;
            return 0;
        }
        int num;
        char *t = new char[num];
        char *v = new char[3];
        fin>>num;
        fin.getline(t,num);
        cout<<"size::"<<num<<endl;
        int pos = 1;
        for(int i=1;i<num;i++)
        {
            fin.getline(t,num);
            fin.getline(v,num);
            if(v[0] == '\0')
            {
                fin.getline(v,num);
                v[0] = '\n';    
            }
            CreatTree(t, v[0], pos);
            v[0]=0;
        }
    
        int zero;
        long long size;
        fin>>zero; fin>>size;
        fin.getline(t,num);
        fin.read(str,sizeof(char)*size);
        print(zero, size, str);
    
        cout<<"zero::"<<zero<<endl;
    
        return 0;
    }

    代码读写操作用文件流实现,所以在时间效率方面还有很多可优化的地方,待日后闲了再说,毕竟考试在即。。。如果哪里有错误,欢迎砸砖,便于在下提升修正。

    展开全文
  • 文本编码

    万次阅读 2016-03-01 00:05:49
    文本编码 文本编码这个问题自三年前就困扰着我,当时是用Python处理多国语言时出现的bug,最后问题解决了,但其中具体逻辑并不懂。后来零零散散接触了不少资料,算是大致弄明白,记录如下。 unicode与ascii等编码...

    文本编码

    • 文本编码这个问题自三年前就困扰着我,当时是用Python处理多国语言时出现的bug,最后问题解决了,但其中具体逻辑并不懂。后来零零散散接触了不少资料,算是大致弄明白,记录如下。

    unicode与ascii等编码方案

    ascii

    • ascii编码方案一共规定了128个字符对应的二进制表示,只占用了一个字节的后面7bit,最高位为0
    • 欧洲国家使用128个符号不足以表示所有字母,使用了最高位。因此不同的国家128~255表示不同的符号,并不通用,即为扩展的ascii码,包括ISO-8859-1~15。这些都是单个字节编码。
    • ISO-8859-1
      • ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中
      • ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃
      • Latin1是ISO-8859-1的别名,有些环境下写作Latin-1

    gb2312

    • 一种双字节编码,包含6763个汉字

    gbk

    • 对gb2312的扩展,可以表示21003个汉字,兼容gb2312

    gb18030

    • unicode的一种天朝实现
    • 采用单、双、四字节编码,兼容gb2312

    base64

    • base64使用64个可打印字符表示二进制数据。每个单元包含6bit。转换后每76个单元要加上一个换行符。
    • 可打印字符包括:A-Z a-z 0-9以及两个其他不定符号,大部分实现为+ /
    • 将每3个字符编码为4个单元,不足3个的用=补足

    unicode

    • unicode试图表示所有的字符
    • 采用unicode的系统、平台有:
      • windows NT及后续系统、java采用utf16作为内置编码
      • .net, mac, kde同样使用unicode
      • utf-8是unix-like操作系统的主要存储编码方案
      • utf-8是html文件最常用的unicode编码
      • XML及其子集XHTML采用UTF-8作为标准字集
    • 编码方案
      • 对每个字符规定了一个码点:code point
      • unicode现在包括17个平面,每个平面最多可以存放65536个字符,也即需要至少21个bit才足够表示所有码点。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0016到1016,共计17个平面
      • 首先的256个字符编码与ISO-8859-1相同
      • 表示方式为U+紧跟十六进制表示。基本平面(BMP U+0000到U+FFFF)中采用四个数字(2byte),16个辅助平面(SMP U+10000到U+10FFFF)中采用5~6个数字
    • 实现方案
      • 实现方案包括Unicode Transformation Format (UTF)和Universal Coded Character Set (UCS)两种
      • unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)
      • utf8:8bit变长编码,详细实现见下一节
      • utf16:16bit变长编码,下有详述
      • utf32:32bit定长编码,完全对应unicode
      • usc-2:2byte定长编码,utf16的子集,JavaScript使用此编码方案。因为不能表示更多字符,后续在此基础上发展出了utf16
      • usc-4:等价于utf32
      • gb18030
    • utf16
      • 对BMP中的字符使用2byte表示,SMP使用4byte
      • BMP从U+D800到U+DFFF之间的码位区段是永久保留不映射到Unicode字符
      • 辅助平面的字符位共有2^20个,也就是说,对应这些字符至少需要20个二进制位。UTF-16将这20位拆成两半,前10位映射在U+D800到U+DBFF(空间大小2^10),称为高位(H),后10位映射在U+DC00到U+DFFF(空间大小2^10),称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。
      • 对于两个字节,发现它的码点在U+D800到U+DBFF之间,就可以断定,紧跟在后面的两个字节的码点,应该在U+DC00到U+DFFF之间,这四个字节必须放在一起解读。

    utf8

    • 采用1~4个byte对unicode进行编码,每个字元只有1byte,不存在字节序问题
    • unicode和utf8编码对应关系

        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
      • 单字节字符的最高有效比特永远为0。
      • 多字节序列中的首个字元组的几个最高有效比特决定了序列的长度。最高有效位为110的是2字节序列,而1110的是三字节序列,如此类推。
      • 多字节序列中其余的字节中的首两个最高有效比特为10
      • 具体为何根据这样麻烦的规则编码呢?一是防止解码出现歧义,二是尽量压缩存储空间。如果学过编码理论或者信息论应当很容易明白。
    • 相对于utf16
      • utf16编码效率/性能较高,字符到字节转换更为方便
      • utf8消耗存储空间较少

    文本和IO

    • IO时经常需要对文本进行编解码或编码格式转化
    • 在硬盘文件中:以文件编码格式存储
    • 在内存中:java和c#用utf16
    • 如何显示在屏幕上:显卡驱动(虚拟设备)根据输入字节及编码渲染
    • 网络:按照应用层商定的协议编解码

    utf8和BOM

    什么是BOM

    • BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节序(byte order)。
    • utf不同编码实现的BOM定义:
      • UTF-8 EF BB BF
      • UTF-16(大端序) FE FF
      • UTF-16(小端序) FF FE
      • UTF-32(大端序) 00 00 FE FF
      • UTF-32(小端序) FF FE 00 00
    • 对于utf8,没有字节顺序的议题。UTF-8编码过的字节顺序标记则被用来标示它是UTF-8的文件。它只用来标示一个UTF-8的文件,而不用来说明字节顺序。
    • 对于utf16和utf32,用来表示大端还是小段
    • BOM相当于魔数(magic number)
      • 图像文件、ELF文件、class文件都存在魔数
      • linux命令file能根据魔数(libmagic)判断文件类型
      • 文件扩展名更重要的作用是让系统决定当用户想打开这个文件的时候用哪种软件运行,如Windows系统中exe文件是可执行档,doc文件默认用Microsoft Word打开的Word文件。

    记事本四种另存为的编码格式

    • ANSI(对于英文系统即ASCII编码,中文系统则为GB2312或Big5编码)
    • “Unicode”(对应UTF-16 LE)
    • “Unicode big endian”(对应UTF-16 BE)
    • “UTF-8”:带 BOM 的 UTF-8

    使用utf8不要包含BOM

    • 不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯(顺便提一下:把带有 BOM 的小端序 UTF-16 称作「Unicode」而又不详细说明,这也是微软的习惯)。微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 ASCII 等编码明确区分开,但这样的文件在 Windows 之外的操作系统里会带来问题。
    • 许多windows程序(包含记事本)会添加字节顺序标记到UTF-8文件。然而,在类Unix系统中,这种作法则不被建议采用。因为它会妨碍到如shell脚本开头的一些重要的码的正确处理。它亦会影响到无法识别它的编程语言。

    参考

    wiki:BOM
    wiki:Unicode

     
     

    转载请注明作者:Focustc,博客地址为 http://blog.csdn.net/caozhk,原文链接为 点击打开

    展开全文
  • 文章目录一、 Index编码二、 OneHot编码独热编码优缺点什么情况下(不)用独热编码?什么情况下(不)需要归一化?三、 Multiple编码如何使用Multiple编码呢?四、 编码比较参考文献 一、 Index编码 用来对离散的类型...

    一、 Index编码

    用来对离散的类型特征进行编码,如,不连续的数值、文本,将离散的特征转换成连续的数值型变量。基于索引的编码可以起到数据归一化的作用,如,id为1和10000,当id作为LR的特征时,id为1的用户和id为10000的用户基本属性一样,但LR算法中10000权重过大,会导致id=1的特征基本不起作用,必须进行归一化,类似特征都应单独进行归一化。

    如特征A取值共有9种情况,如,[1, 200, 10000, 30000, 100000],则索引编码后为[0, 1, 2, 3, 4]。

    代码示例:

    from sklearn.preprocessing import LabelEncoder
    a = [1, 200, 10000, 30000, 100000]
    label_coder = LabelEncoder()
    label_coder.fit(a)
    b = label_coder.transform(a)
    print(b)
    

    二、 OneHot编码

    OneHot编码也叫独热编码或哑编码,可以解决某些分类器不好处理离散属性数据的问题,在一定长度上也起到了对特征进行扩充的作用。

    大部分算法是基于向量空间中的距离度量来进行计算的,为了使非偏序关系的变量取值不具有偏序性,并且到圆点是等距的。使用one-hot编码,将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。将离散型特征使用one-hot编码,会让特征之间的距离计算更加合理。离散特征进行one-hot编码后,编码后的特征,其实每一维度的特征都可以看做是连续的特征。跟对连续型特征的归一化方法一样,对每一维特征进行归一化。比如归一化到[-1,1]或归一化到均值为0,方差为1。

    为什么特征向量要映射到欧式空间?

    在回归,分类,聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的,而我们常用的距离或相似度的计算都是在欧式空间的相似度计算,如,计算余弦相似性,就是基于欧式空间。

    代码示例:

    from sklearn.preprocessing import OneHotEncoder
    onehot_coder = OneHotEncoder()
    onehot_coder.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
    c = onehot_coder.transform([[0, 0, 3]])
    print(c.toarray())
    

    独热编码优缺点

    优点:独热编码解决了分类器不好处理属性数据的问题,在一定程度上也起到了扩充特征的作用。它的值只有0和1,不同的类型存储在垂直的空间。

    缺点:当类别的数量很多时,特征空间会变得非常大。在这种情况下,一般可以用PCA来减少维度。而且one hot encoding+PCA这种组合在实际中也非常有用。

    什么情况下(不)用独热编码?

    • 用于类别型数据的离散值。

    • 不用

      让距离计算更合理,但如果特征是离散的,并且不用one-hot编码就可以很合理的计算出距离,那么就没必要进行one-hot编码。 有些基于树的算法在处理变量时,并不是基于向量空间度量,数值只是个类别符号,即没有偏序关系,所以不用进行独热编码。 Tree Model不太需要one-hot编码: 对于决策树来说,one-hot的本质是增加树的深度。

    总的来说,要是oneHot encoding的类别数目不太多,即升维不大,建议优先考虑。

    什么情况下(不)需要归一化?

    • 需要

      基于参数的模型或基于距离的模型,都是要进行特征的归一化。

    • 不需要

      基于树的方法不需要进行特征的归一化,例如随机森林,bagging 和 boosting等。

    三、 Multiple编码

    顾名思义,Multiple编码特征将多个属性同时编码到一个特征中。在推荐场景中,单个用户对哪些物品感兴趣的特征就是一种Multiple编码特征,如,表示某用户对产品1、产品2、产品3、产品4是否感兴趣,则这个特征可能有多个取值,如用户A对产品1和产品2感兴趣,用户B对产品1和产品4感兴趣,用户C对产品1、产品3和产品4感兴趣,则用户兴趣特征为

    用户UserInterests
    A[1, 2]
    B[1, 4]
    C[1, 3, 4]

    Multiple编码采用类似oneHot编码的形式进行编码,根据物品种类数目,展成物品种类数目大小的向量,当某个用户感兴趣时,对应维度为1,反之为0,如下

    用户UserInterests
    A[1, 1, 0, 0]
    B[1, 0, 0, 1]
    C[1, 0, 1, 1]

    代码示例:

    from sklearn.preprocessing import LabelEncoder
    d = [[1, 2], [1, 4], [1, 3, 4]]  // 原始特征
    e = set()
    for i in d:  // 求d中所有物品类别
        for j in i:
            e.add(j)
            
    // 对d中物品进行Index编码
    label_coder = LabelEncoder()
    label_coder.fit(list(e))
    
    // 特征[1, 2]进行编码
    f = [0]*len(e)
    for i in label_coder2.transform([1, 2]):
        f[i] = 1
    print(f)
    //[1, 2] 转换后为 [1, 1, 0, 0]
    

    如何使用Multiple编码呢?

    我们将多个属性同时编码到同一个特征中,目的就是同时利用多个属性的特征。经过Multiple编码后的特征大小为[batch_size, num_items],记作U,构建物品items的Embedding矩阵,该矩阵维度为[num_items, embedding_size],记作V,将矩阵U和矩阵V相乘,我们就得到了大小为[batch_size, embedding_size]的多属性表示。

    上述过程实现了多维多属性特征的构建,该手段在深度学习特征工程中被广泛应用。

    四、 编码比较

    以下通过应用场景对以上3种编码方式进行比较:

    • 当离散型特征的方差较大,即相似特征取值差异较大时,需要进行归一化,可采用Index编码;

    • 当所使用的算法基于空间向量时,需要进一步对特征进行oneHot编码,需要注意避免维度爆炸,当维度较大时应考虑采用降维方法,如PCA;

    • 当需要对特征进行多维编码时,可采用Multiple编码,多维度多属性特征的构建可以在此基础上增加Embedding的特征得到;

    参考文献

    1. OneHotEncoder独热编码和 LabelEncoder标签编码
    2. multi-hot编码原理
    展开全文
  • 字符编码那些事--彻底理解掌握编码知识

    千次阅读 多人点赞 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
    还有一些其他文章的资料就不一一列举了。

    展开全文
  • 编码之Base64编码

    万次阅读 2019-10-01 09:22:46
    Base64编码是一种基于 64 个可打印字符来表示二进制数据的方法。目前 Base64 已经成为网络上常见的传输 8 位二进制字节代码的编码方式之一。 为什么会有 Base64 编码呢?因为有些网络传送渠道并不支持所有的字节,...
  • 一篇文章彻底弄懂Base64编码原理

    万次阅读 多人点赞 2018-08-16 07:42:09
    目前Base64已经成为网络上常见的传输8Bit字节代码的编码方式之一。在做支付系统时,系统之间的报文交互都需要使用Base64对明文进行转码,然后再进行签名或加密,之后再进行(或再次Base64)传输。那么,...
  • base64两种编码不同《注意》

    千次阅读 2018-12-14 18:51:02
    分为有无==的两种 无== 有==
  • 常见视频编码格式解析

    万次阅读 多人点赞 2017-12-15 14:12:56
    常见视频编码格式解析 常见视频编码格式解析 1.MPEG2-TS编码技术 1.1.MPEG-TS简介 1.2.基本概念及TS流概述 1.3.基本流程 1.4.TS流传输包(简称TS包)结构分析 1.4.1.TS包包头 1.4.2.TS包净荷部分 1.5.PS节目流 ...
  • 类别特征的独热编码和二进制编码

    千次阅读 2019-09-23 19:08:22
    我们在建模之前,一般需要对数据进行预处理...1)独热编码:独热编码会将变量的不同取值(N种取值)分别赋予一个只有1位为0的N维向量。例如星期,共有7个取值,独热编码会把它编码成一个7维稀疏向量。星期一表示为(...
  • 信道编码科普

    千次阅读 2020-09-14 22:35:13
    信道编码信道编码的意义实现途径信道类型,错码特性,差错控制技术一一对应匹配检错纠错能力纠错编码类型分组码卷积码特别说明-Turbo码特别说明-LDPC码网格编码调制 信道编码的意义 在信号传输过程中,由于受到干扰...
  • EPC 编码

    千次阅读 2016-03-25 16:40:40
    现在世界上的物联网有三大应用架构,分别是基于RFID、传感网络、M... 目前,国际上还没有统一的RFID编码规则。为了更好地推动RFID产业的发展,国际标准化组织ISO、以美国为首的EPCglobal、日本UID等标准化组织纷纷制定
  • 特征编码

    千次阅读 2018-11-02 16:30:02
    特征编码 机器学习模型需要的数据是数字型的,因为只有数字类型才能进行计算,而我么你平时处理到的一些数据是很多是符号的,或者是中文的。所以编码是必要的,对于各种各样的特征值去编码实际上就是一个量化的过程 ...
  • 文本文件编码 email编码

    千次阅读 2015-01-08 09:54:50
    来源: ChinaUnix博客 日期: 2007.05.10 10:46 (共有条评论) 我要评论   简单介绍一下这四种编码方式:  ANSI:系统预设的标准文字储存格式。ANSI是American National Standards Institute的缩写。...
  • Base64 编码介绍

    千次阅读 2014-01-08 12:46:46
    在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后binhex的版本使用不同的64字符集来代表6个二进制数字,但是...
  • 数字-数字编码和模拟-数字编码

    千次阅读 2019-11-30 16:02:53
    一般来说,共有四种编码方式: 数字-数字 模拟-数字 数字-模拟 模拟-模拟 数字-数字编码 数字-数字编码是用数字信号来表示数字信息。 它们可以归为三大类: 1. 单极性编码 单极性编码的名称是指它的电压只有一极,...
  • 编码

    千次阅读 2013-03-22 21:30:08
    本章先介绍熵的基本概念,然后介绍香农-范诺(Shannon-Fano)编码、哈夫曼(Huffman)编码、算术编码(arithmetic coding)、行程编码(RLE)和LZW编码等常用的熵编码方法。 1 熵 熵(entropy)本来是热力学中用来度量热力...
  • Base64编码

    千次阅读 2013-01-28 14:39:18
    Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个位元为一个单元,对应某个可打印字符。... ,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuen
  • DNA编码

    千次阅读 2017-12-27 14:42:19
    DNA编码的学习—-笔记1 虽然一万个不想学这个东西,但还是要先了解一些。书名《DNA编码序列的设计与优化》 第一章 DNA的计算 主要讲了DNA计算相关的内容。 首先说了DNA为什么出现,分子水平的研究成熟,数学上...
  • 对 n 个互不相同的符号进行哈夫曼编码。若生成的哈夫曼树共有 115 个结点,则 n 的值是:(2分) A.56 B.57 C.58 D.60 作者: 考研真题 答案:C 解题思路: 哈夫曼树的特点性质:(节点为的度数为0 表示 n0,以此类推) ...
  • 在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外的两个可打印符号在不同的系统中而不同,一般为+和/。 转换原理 Base64的直接数据源是二进制序列(Binary Sequence)。当然,你也可以将图片...
  • 编码之CABAC

    千次阅读 2017-10-12 17:27:47
    CABAC(Context-based Adaptive Binary Arithmetic Coding),基于上下文的自适应二进制算术编码。CABAC是H.264/AVC标准中两种熵编码中的一种,它的编码核心算法就是算术编码(Arithmetic Coding)。   算术编码 ...
  • Base64编码编码性能测试

    千次阅读 2013-12-03 16:36:23
    原创文章,欢迎转载。转载请注明出处: ...在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。 具体可参照维基百科:维基百科 Base64
  • Unicode编码

    千次阅读 2015-02-11 15:28:27
    在前面一篇博文中介绍了UTF-8编码实现,并简单介绍了Unicode编码。它们之间的关系就是字符的抽象与实现的关系。在抽象的字符集中,每个字符通过唯一的code point码位(一个整数,一般用十六进制)表示。但是在实际...
  • bcd编码

    千次阅读 2013-12-06 14:47:23
    是一种二进制的数字编码形式,用二进制编码的十进制代码。BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行。这种编码技巧最常用于会计系统的设计里,因为会计...
  • H.265编码和H.264编码的区别

    万次阅读 2019-09-17 14:50:00
    H.264和H.265有何不同? 一、什么是H.265 H.265是ITU-TVCEG继H.264之后所制定的新的视频编码标准。H.265标准围绕着现有的视频编码标准H.264,保留原来的某些技术,同时对一些相关的技术加以改进。 新技术使用先进...
  • 编程与编码

    千次阅读 2016-02-19 01:44:00
    编程与编码 MD建档时间:2016年2月18日 4:46:47 PM by Jimbowhy CSDN发布: 问题由来在计算产生的那天开始,应该说计算产生之前,编码问题就会一直伴随着信息编码的问题。这是由于计算机硬件逻辑上决定的,电路的二...
  • MPEG2视频编码简介

    千次阅读 2019-04-20 17:42:17
    MPEG-2视频编码简介 MPEG-2是一组用于视音频压缩编码及其数据流封装的国际标准。它定义了编解码技术及数据流的传输协议;制定了MPEG-2解码器之间的共同标准。编码是MPEG-2标准的核心内容之一,其涉及到MPEG-2视频流...
  • CABAC编码解析

    万次阅读 2017-04-26 20:42:28
    CABAC(Context-based Adaptive Binary Arithmetic Coding),基于上下文的自适应二进制算术编码。CABAC是H.264/AVC标准中两种熵编码中的一种,它的编码核心算法就是算术编码(Arithmetic Coding)。   算术...
  • 共有三种编码的方式:用于信道质量信息CQI编码,用于HARQ-ACK和调度请求的编码,用于信道质量信息和HARQ-ACK的混合编码。 2、 HARQ-ACK 编码:1代表有效,0代表无效  CQI编码:(20,A)的码块进行编码,该码块是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 56,056
精华内容 22,422
关键字:

不同的编码共有