黑马程序员技术交流社区

标题: Unicode的不解之处 [打印本页]

作者: sanguodouble1    时间: 2014-5-25 16:43
标题: Unicode的不解之处
本帖最后由 sanguodouble1 于 2014-5-29 22:37 编辑

今天看到一道关于字符集的笔试题,然后总结了一下:
ASCII :英文一个字节
gb2312,gbk :中文两个字节,英文一个字节
       在中文系统中ansi一般指gb2312或gbk
       GB2312、GBK都属于双字节字符集 (DBCS)
Utf-8 :中文三个字节,英文一个字节
Unicode:中文两个字节,英文两个字 ,java中默认编码
以上我的理解没错吧?

如果没错的话,下面这个使我十分不解:

  1. public class Test {
  2.         public static void main(String[] args) throws UnsupportedEncodingException {
  3.                 String str1 = "我爱abc";
  4.                 String str2 = "a";
  5.                 byte[] buf1 = str1.getBytes("unicode");
  6.                 byte[] buf2 = str2.getBytes("unicode");
  7.                 System.out.println(buf1.length+"字节");
  8.                 for (byte c : buf1) {
  9.                         System.out.print(c + " ");
  10.                 }
  11.                 System.out.println();
  12.                 System.out.println(buf2.length+"字节");
  13.                 for (byte c : buf2) {
  14.                         System.out.print(c + " ");
  15.                 }
  16.         }
  17. }
复制代码
输出结果:
str1-----------12字节
-2 -1 98 17 114 49 0 97 0 98 0 99
str2-----------4字节
-2 -1 0 97


理论上,str1应该是10个字节,str2是两个字节啊
现在多出来了两个字节-2和-1,这个是什么东西呢?

作者: sanguodouble1    时间: 2014-5-26 20:04
:o:o:o:o:o
作者: 向前看向前走    时间: 2014-5-26 21:39
这个问题我也没有见过,搜集了一下资料,自己也学习整理了一下,楼主可以参考下
Unicode规范中推荐的标记字节顺序的方法是BOM
1、所以在转换为Unicode是加入了BOM (Byte Order Mark) 可以理解为采用那种排序方式吧
2、如果接收者收到FEFF(-1,-2),就表明这个字节流是Big-Endian的;如果收到FFFE(-2,-1),就表明这个字节流是Little-Endian的。
3、在 Java 中直接使用Unicode 转码时会按照UTF-16LE 的方式拆分,并加上 BOM所以就是FFFE(-2,-1),
这就是为什么会有-2,-1了,Unicode
4、UTF8字节没有顺序,所以它可以被用来检测一个字节流是否是UTF-8编码的,所以在UTF-8 中没有这个内容,我们平时用UTF-8比较多,所以看不到这个。
  希望楼主多发这样的问题,大家一块学习


作者: sanguodouble1    时间: 2014-5-26 23:04
向前看向前走 发表于 2014-5-26 21:39
这个问题我也没有见过,搜集了一下资料,自己也学习整理了一下,楼主可以参考下
Unicode规范中推荐的标记字 ...

非常好
不过我估计Utf-8之所以没有BOM头,是因为utf-8可以根据每个字节的前几位来判定,


作者: TS__likewise    时间: 2014-5-27 07:27
额,-2 -1(FE FF)是unicode big endian标志
fe ff:big endian
ff fe: no big endian
按照上面的结果看好像一个char是3 byte,但java中一个char是2 byte,
其实java中无论什么字符集string都会以unicode编码来存储,所以每个char都是一个
unicode编码占两个byte。

import java.io.UnsupportedEncodingException;  
  
  
public class TestUtf8File {  
  
  /** 
   * @param args 
   * 
   */  
  public static void main(String[] args) throws UnsupportedEncodingException {  
  
    String s = "中国人";     
    byte[] b = s.getBytes("utf-8");  
    String s_utf8 = new String(b,"utf-8");  
    System.out.println(s_utf8.getBytes("utf-8").length);  
    System.out.println("utf-8 bytes:");  
    printByteArray(s_utf8.getBytes("utf-8"));  
    System.out.println("chars:");  
    printCharArray(s_utf8.toCharArray());  
      
    byte[] unicodeb= s.getBytes("unicode");  
    String s_unidode = new String(unicodeb,"unicode");  
    System.out.println("unicode bytes:");  
    printByteArray(s_unidode.getBytes("unicode"));  
  
  }  
    
  private static void printByteArray(byte[] b){  
    for(int i = 0;i < b.length; i++){  
      System.out.println((Integer.toString(b[i],16)));  
        
    }  
  }  
    
  private static void printCharArray(char[] c){  
    for(int i = 0;i < c.length; i++){  
      System.out.println(Integer.toString((byte)(c[i]>>8),16));  
      System.out.println(Integer.toString((byte)(c[i]&0xff),16));  
        
    }  
  }  
  
}  

结果是output:
9
utf-8 bytes:
-1c
-48
-53
-1b
-65
-43
-1c
-46
-46
chars:
4e
2d
56
-3
4e
-46
unicode bytes:
-2
-1
4e
2d
56
-3
4e
-46
作者: 向前看向前走    时间: 2014-5-27 08:58
sanguodouble1 发表于 2014-5-26 23:04
非常好
不过我估计Utf-8之所以没有BOM头,是因为utf-8可以根据每个字节的前几位来判定,

你可以再看看这个,就应该能理解了
UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?
  UTF-8是不用排序的,而Unicode是可以多个字节表示的,是需要排序的。
作者: 博€$€海    时间: 2014-6-1 21:27
在 Java 中直接使用Unicode 转码时会按照UTF-16LE 的方式拆分
作者: 、海    时间: 2014-6-12 19:38
学习了!!


作者: 沐子松/kf    时间: 2014-6-13 12:41
学习          
作者: hmid    时间: 2014-6-21 20:28
学习,顶
作者: 何艳梅    时间: 2014-8-19 22:49
学习了  
作者: Lscreat    时间: 2014-11-19 15:56
学习了啊,谢谢啊。
作者: xuelanghu120    时间: 2015-5-10 10:29
非常好   见识了
作者: 15225159271    时间: 2015-7-29 09:50
前几位总结的挺好,学习方法受教了
作者: 灵韵依存    时间: 2015-11-19 22:23
围观中。。。。学习大神结论
作者: 蓦然回首102    时间: 2015-11-27 13:45
楼主给力!!!
作者: 376699155    时间: 2016-1-15 11:37
牛逼,学习了!
作者: docwei    时间: 2016-2-25 23:26
看不懂啊啊啊啊
作者: 图兰朵    时间: 2016-3-28 02:37
顶一下!!!!
作者: 图兰朵    时间: 2016-3-28 02:41
顶一个!!!!
作者: innovator    时间: 2016-5-17 13:03
暂时看不懂...先收藏之后再研究。楼主很赞,分享很给力
作者: fanhongwei1105    时间: 2016-5-24 00:15
UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?
  UTF-8是不用排序的,而Unicode是可以多个字节表示的,是需要排序的。
作者: DGNT00    时间: 2016-7-10 11:57
涨见识了,萌新表示原来还有这么多讲究




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2