字符编码杂谈

来源:互联网 发布:网络贷款公司合法的吗 编辑:程序博客网 时间:2024/06/03 19:38

字符编码杂谈

基础知识准备

字符编码笔记:ASCII,Unicode和UTF-8

准备工具

notepad++添加16进制插件
可以使用这个工具查看编码

Unicode与UTF-8的异同

  1. Unicode只是一个符号集,它只规定了符号的二进制代码,而不是二进制代码的一种存储方式。而utf-8、gbk、ascII它们有自己的编码集,但同时也是一种存储方式。
  2. UTF-8把字符的Unicode编码根据大小进行分类存储,有的使用一个字节,有的使用两个字节甚至更多,而Unicode编码都是两字节及上,所以说UTF-8也算是对Unicode进行了压缩处理,由于UTF-8对应一个字符所用字节是不定的,所以在编码时,应该把几个字节代表一个字符给编写进去,这样每个字节的前几位会被占用,只有之后的几位用来存储这些字符的unicode编码,所以UTF-8是Unicode的实现存储的方式之一。

    已知”严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此”严”的UTF-8编码需要三个字节,即格式是”1110xxxx 10xxxxxx 10xxxxxx”。然后,从”严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,”严”的UTF-8编码是”11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

正则表达式中文校验

小知识点:
\uxxxx这种格式是Unicode写法 Ox\x都是16进度的一种写法

在C语言、C++、JAVA中:
八进制的前缀是O 举个数子:O51 这个数就表示是八进制的数
十六进制的前缀是Ox : Ox9B4,这个数就表示是十六进制的数值。

[\u4e00-\u9fa5]//中文(对生僻字无效如:)[^\x00-\xff]//匹配双字节字符(包括汉字在内)[^\Ox00-\Oxff]//

同一个字的不同的Unicode编码

看着是同一个字,但对电脑来说是不同的字,如“”和“䶮”看着是同一字,其实它们的unicode的编码确是不一样的,第一个字是用搜狗五笔打出来的,第二个字是用搜狗拼音打出来,搜狗五笔中有一项设置在GBK中搜索生僻字,所以搜狗五笔打出来的是GBK格式的,而搜狗拼音里是没有这个选项的,打出来是Unicode编码,在window下的记事本notepad里打出第二个字,点存在时,会提示有Unicode编码,所以可以断定第二个字是Unicode编码。而第一个字转成Unicode的编码和第二个Unicode的编码还是不一样的,说明Unicode编码对这两个字符都有相应的编码,而GBK只对第一个进行了编码。通过在线Unicode转换工具也可以看出第一个字“”的Unicode编码是:\ue863,而第二个字“䶮”的Unicode编码是\u4dae

Unicode编码是对各国文字的汇总再编码,各国文字存在重复的情况,最终会出现看着是同一个文字却被Unicode收录了两字,并拥有各自不同的编码。而GBK所对应的文字也都被Unicode收录并给予相应的Unicode编码,但由于是分批汇总的可能会出编码不在同一区域,也是就是编码不是连续的。而Unicode收录的文字,如第二个字符(用搜狗拼音打出来的)没有被GBK收录,所以在GBK编码的文件中这个字符会出现乱码的情况,变成了一个问号“?”,这个字符在GBK字符集中是找不到编码的,最终会给一个ASCII码为3f的问号“?”来代替,这样的话就会出现一个问题,即使现在把文档改成Unicode编码也是回不去了,因为原编码已经丢失被强行改成3f了,但如果一个GBK文件被用Unicode格式打开出现了乱码(一堆以X开头16进制的数字文件),此时再重新用GBK编码格式打开,就会恢复,所以可能出现一种规则,小范围的字符集错用大字符集格式保存是可以恢复的,但大字符集用小字符集保存就恢复不回来了,因为大字集在小字符集中找不到对应编码就会强行改成问题“?”,数据已经“失真”了,只有部分有能找到编码的字符可以恢复,而打不到编码被强行修改编码的字符想恢复是不可能了。这样也就会引出一个判断字符是不是GBK格式的方法,见下文。

如何判断字符是不是GBK编码

方法就是得到这个字符串所对应的GBK编码,再new一个用GBK编码的字符串出来,然后与之前的那个字符进行equals比较,相同则能被GBK所识,不同说明GBK未收录这个字符,那样用GBK存储就会出现乱码。如果不是一个GBK字符或者说没有被GBK收录的字符,在第一步得到GBK编码时,数据就已经失真,之后是无法再这个数据new出一个与之前字符相同的字符来的。

        String nameString="马";        String nameString2="马䶮";        System.out.println(new String(nameString.getBytes("gbk"),"gbk").equals(nameString));//返回true        System.out.println(new String(nameString2.getBytes("gbk"),"gbk").equals(nameString2));//返回false

数据库字符集还是不要用GBK

从上面的得知有一个文字,看成是汉字,但没有被GBK收录,存储在GBK格式的文件中会出现乱码的情况,同样如果有一个文字(用搜狗拼音打出来的一个Unicode编码的汉字)想存储在GBK格式的数据库中,也会现乱码情况,所以数据库的字符集还是不要设置为GBK为好。

GBK所占字节

ASCII 英文一个字节
gb2312,gbk 中文两个字节,英文一个字节(半角状态);
在中文系统中ansi一般指gb2312或gbk;
GB2312、GBK都属于双字节字符集 (DBCS)
Utf-8 中文三个字节,英文一个字节
Unicode 中文两个字节,英文两个字

原创粉丝点击