??xml version="1.0" encoding="utf-8" standalone="yes"?>国产中文欧美日韩在线,日韩精品一区二区三区中文不卡,日本在线观看一区二区三区http://www.aygfsteel.com/iamct/category/51417.htmlzh-cnWed, 18 Apr 2012 07:13:37 GMTWed, 18 Apr 2012 07:13:37 GMT60java ~码 http://www.aygfsteel.com/iamct/archive/2012/04/18/375059.htmliamctiamctWed, 18 Apr 2012 03:38:00 GMThttp://www.aygfsteel.com/iamct/archive/2012/04/18/375059.htmlhttp://www.aygfsteel.com/iamct/comments/375059.htmlhttp://www.aygfsteel.com/iamct/archive/2012/04/18/375059.html#Feedback0http://www.aygfsteel.com/iamct/comments/commentRss/375059.htmlhttp://www.aygfsteel.com/iamct/services/trackbacks/375059.html?天同事有询问相关~码的问题,在此做个整理Q希望能够对大家有所帮助?br />
首先是编码的历史Q这是一?a title="很有意思的解读" href="http://www.aygfsteel.com/iamct/articles/374954.html">很有意思的解读 。写的很q默Q便于理解?br />
下面主要写于与java惛_的编码,主要解读unicode Qutf8 和gbk?br />
JVM里面的Q何字W串资源都是UnicodeQ就是说QQ何Stringcd的数据都是Unicode~码。没有例外,因此我们可以q么_JVM里面的String是不带编码的。因Z有且只对应一UUnicode?/div>
一个字W的Unicode~码是确定的。也是说Unicode是一U字W集Q里面字W与~码是一一对应的,q里有个码表可查,unicode 码表。但是在实际传输q程中,׃不同pȝq_的设计不一定一_以及Z节省I间的目的,对Unicode~码的实现方式有所不同。Unicode的实现方式称?strong>Unicode转换格式QUnicode Transformation FormatQ简UCؓUTFQ。我们常用的是UTF8.
UTF8是如何存储一个Unicode~码的呢。也是utf8作ؓ一UUnicode Transformation Format是如何工作的呢?
首先utf8 是可变长的,UTF-8使用一臛_个字节ؓ每个字符~码。参照下表,我们把精力放在第1列,W?列,和注释?br />
对于ASCII字符Q可以用七个bit位来表示Qx6 x5 x4 x3 x2 x1 x0.W八个bit永远??br />
W?28?047个字节,要用10个bit来表C,110yyyyy(C0-DF) 10zzzzzz(80-BF)
W?048?5535个字节,要用16个bit来表C,Utf-8把这些字节编成下面这L三个byte?110xxxx(E0-EF) 10yyyyyy 10zzzzzz
大于65535其余?个byte来表C?br />
举个例子Q?#8220;中国”的中Qunicode~码?#8220;\u4e2d", 对应的编码除了查表,java可以用命令行Q运?native2ascii q行转化?br />用window 自带的附件中的计器Q查?>U学型)Q{化成10q制?0013Q二q制?span style="color: red;">100111000101101 
通过上面的表Q可知,转化成utf8后ؓ三个字节?br />
只需要将刚才转化的二q制Q上面标U的Q将下面的xxxxQyyyyyyQzzzzzz补齐卛_?br />
1110xxxx(E0-EF) 10yyyyyy 10zzzzzzQ我们从低位开始补P不够的用0补齐?br />11100100 10111000 10101101  Q换?6q制为E4 B8 AD?
好了我们用java代码来验证下Q是否正?br />
public static void main(String[] args) {
        String ha 
= "?/span>";
        
byte b[] = null;
        
try {
            b 
= ha.getBytes("utf-8");
        } 
catch (Exception e) {
            System.exit(
-1);
        }

        
for (int i = 0; i < b.length; i++) {
            System.out.print(Integer.toHexString(b[i]).substring(
6+ " ");
        }

    }
输出果然是:e4  b8 ad?br />utf8 wiki中有下描qͼ
  • 对于UTF-8~码中的L字节BQ如果B的第一位ؓ0Q则B为ASCII码,q且B独立的表CZ个字W?
  • 如果B的第一位ؓ1Q第二位?Q则BZ个非ASCII字符Q该字符由多个字节表C)中的一个字节,q且不ؓ字符的第一个字节编?
  • 如果B的前两位?Q第三位?Q则BZ个非ASCII字符Q该字符由多个字节表C)中的W一个字节,q且该字W由两个字节表示;
  • 如果B的前三位?Q第四位?Q则BZ个非ASCII字符Q该字符由多个字节表C)中的W一个字节,q且该字W由三个字节表示;
  • 如果B的前四位?Q第五位?Q则BZ个非ASCII字符Q该字符由多个字节表C)中的W一个字节,q且该字W由四个字节表示;

因此Q对UTF-8~码中的L字节Q根据第一位,可判断是否ؓASCII字符;Ҏ前二位,可判断该字节是否Z个字W编码的W一个字? Ҏ前四位(如果前两位均?Q,可确定该字节为字W编码的W一个字节,q且可判断对应的字符由几个字节表C?Ҏ前五位(如果前四位ؓ1Q,可判断编?是否有错误或数据传输q程中是否有错误?/p>


反过来,我们q是拿刚才的”?#8220;ZQ?1100100 10111000 10101101 Q第一个字节开始ؓ110Q则ȝ二个字节?0Q第三个字节?0Q则认ؓ是utf8字符?br />于是有了一个那个经典的“联?q不q?#8221;Ud“的经典段子?br />我们在xp下,随便建立一个文Ӟ输入"联?Q保存,q时你在打开是,发现”联?2个字W不见了。奇怪吗Q?Q?Q?
我们知道默认保存的编码是ANSIQ实际也是类GBK的编码?/div>
对应16q制为c1 aa cd a8Q?转化成二q制?1000001 10101010 11001101 10101000 Q我们来看,110xxxxxQ?0xxxxxx 正好W合utf8的Ş式?br />q时候文件编写器以ؓ你的文g是utf8的文Ӟ然后默认已utf8的Ş式给你打开展示。于是就出现q了。如果你?#8221;联?#8220;后面随便加几个字W。就不出出现灵异事g了?br />
那么我们l箋讨论 GBK和Unicode是什么关pdQ?br />实际上GBK我们可以看做是字W集Q他也有自己一一对应的码表。google一下,很容易查到。这里有个Unicode和GBk对应的表Unicode-GBk?br />在java中,
"我爱你莎?/span>".getBytes("gbk");
q行转化Q其实就是类似查一个Unicode和GBk对应表进行{化的。大家看一下Charsetq个抽象cȝ那些子类明白了?br />通过上面的描qGBk和UTF8关系也就很明朗了Q完全可以通过Unicodeq行中{?br />
同事在询问编码的问题Ӟ一开始对cM如下代码,怺转变不太理解?br />
byte b1[] = null;
        b1 = "我爱你莎?.getBytes("gbk");
        System.out.println(new String(b1,"gbk"));
        byte b2[] = null;
        b2 = "我爱你莎?.getBytes("utf8");
        System.out.println(new String(b2,"utf8"));
        System.out.println(new String (new String (b2,"gbk").getBytes("gbk"),"utf8"));
其实我们可以把getBytesQ?gbk"Q,q个函数当做unicode用gkb加密的过E,而new StringQ?#8221;xxx“Q?~码”Q看成是解密的一个过E?br />
大家思考一下最后面的那个输出可以得到正的l果吗?Z么?

下面我们来讨?Q通过http协议下的url传输后,~码转化问题?br />首先说明的是本h本地默认~码是gbk?br />我们只用ServletQ不使用M框架比如springQ因Z用框架时Q框架也有一套自pq机制Q如下代?br />
public class HttpEncode extends HttpServlet {
    @Override
    
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String str 
= req.getQueryString();
        System.out.println(req.getCharacterEncoding());

        String encode 
= null;
        
try {
            encode 
= req.getParameter("encode");
        } 
catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(str);
        System.out.println(encode);

    }

}
我们分别用jettyQ版?.1Q和resin(版本3.1.8)下容器,试如下h     127.0.0.1/test?encode=%B9%FE  其中%B9%FE为GBk的编码的汉字”?#8220;
jetty容器下输Zؓ
null
encode=%B9%FE
?
resin下ؓQ?br />
null
encode=%B9%FE
null

换做127.0.0.1/test?encode=%E5%93%88   Qutf8~码?#8221;?#8220;
jetty和resin下都输出如下
null
encode=%E5%93%88
?/span>

Z么会是这P
我们拿jetty分析Q在jetty的源码中Q?br />
   public String getParameter(String name)
    {
        
if (!_paramsExtracted) 
            extractParameters();
        
return (String) _parameters.getValue(name, 0);
    }

对应?
extractParameters(); 部分代码
 if (_queryEncoding==null)
                _uri.decodeQueryTo(_baseParameters);
         
然后
   public void decodeQueryTo(MultiMap parameters)
    {
        if (_query==_fragment)
            return;
        _utf8b.reset();
        UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters,_utf8b);
    }






也就是如?span style="color: #000000; ">_queryEncoding为nullӞ默认是用utf8q行解码的。而resin也不例外?br />jetty?span style="color: #000000; ">_queryEncoding的值可以通过org.mortbay.jetty.Request.queryEncoding q个属性给赋Dresin采用的是req.getCharacterEncoding()中的gؓ标准?br />要想在jetty?127.0.0.1/test?encode=%B9%FEQ获取到正确的字W,代码如下
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String str 
= req.getQueryString();
        System.out.println(req.getCharacterEncoding());
        req.setAttribute(
"org.mortbay.jetty.Request.queryEncoding""gbk");
        String encode 
= null;
        
try {
            encode 
= req.getParameter("encode");
        } 
catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(str);
        System.out.println(encode);

    }

resin下只需?br />
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String str 
= req.getQueryString();
        req.setCharacterEncoding(
"gbk");
        System.out.println(req.getCharacterEncoding());
        String encode 
= null;
        
try {
            encode 
= req.getParameter("encode");
        } 
catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(str);
        System.out.println(encode);

    }

通过上面惌明的是,不同的容器,默认~码的策略是不一致的。只要我们了解编码的基础知识。通过一些封装就很容易掌控这个局面?/div>





参考资料:
Unicode wiki:   http://zh.wikipedia.org/wiki/Unicode
jetty 源码


iamct 2012-04-18 11:38 发表评论
]]> վ֩ģ壺 ݸ| | | | ˻| | | | Ǹ| ƽ| | ˫| | | ʢ| ȫ| | | | ³| | | | | | | Դ| ԭ| | ͷ| | | ͨμ| ̨| | ٤ʦ| | Զ| ½| ƽ| ׷|