网址的url编码解码讲解

问题

这是某个网站url的编码,也就是网址所显示的字符。
%E8%AF%84%E8%AE%BA%E7%AE%A1%E7%90%86
原来的内容是
评论管理
这里写图片描述

原理说明

这实际上是url的字符进行encode编码操作,想知道原来的内容是什么则将其decode解码即可。
评论管理进行encode编码操作变成%E8%AF%84%E8%AE%BA%E7%AE%A1%E7%90%86
%E8%AF%84%E8%AE%BA%E7%AE%A1%E7%90%86 进行decode解码即可得到评论管理

API说明

JAVA的url编码解码API说明
URLEncoder.encode(input,”utf-8”):将字符串input使用utf-8编码方式进行url编码。
URLDecoder.decode(output,”utf-8”):将字符串output使用utf-8进行url解码

API使用代码

 String input = "评论管理 abcefg";
 String output = URLEncoder.encode(input,"utf-8");
 String restore = URLDecoder.decode(output,"utf-8");
 System.out.println(output);
 System.out.println(restore);

执行结果:
%E8%AF%84%E8%AE%BA%E7%AE%A1%E7%90%86+abcefg
评论管理 abcefg

Java实现原理说明

这里以URLEncoder.encode进行讲解,URLEncoder.encode方法里使用了BitSet类。
encode方法内首先对Bitset类进行初始化,将大小写字母(a~z,A~Z)、数字(0~9)、空格( )、下划线(_)、中划线(-)、点(.)、星号(*)通过Bitset的set方法加入到符号集中。
执行encode方法时,对输入的字符串s进行遍历,如果s[i]在字符集里,空格转化为+,其余的保持不变,然后加到out数组;
若s[i]不在字符集内,则把连续不在字符集的字符拼接起来,获取其字节数组,然后通过Character.forDigit((ba[j] >> 4) & 0xF, 16)进行编码,最后拼接到out数组,详细内容可以查看下面的代码讲解。

部分代码和讲解

encode方法中BitSet初始化的代码

static BitSet dontNeedEncoding;
 static {
     dontNeedEncoding = new BitSet(256);
     int i;
     for (i = 'a'; i <= 'z'; i++) {
         dontNeedEncoding.set(i);
     }
     for (i = 'A'; i <= 'Z'; i++) {
         dontNeedEncoding.set(i);
     }
     for (i = '0'; i <= '9'; i++) {
         dontNeedEncoding.set(i);
     }
     dontNeedEncoding.set(' '); /* encoding a space to a + is done
                                 * in the encode() method */
     dontNeedEncoding.set('-');
     dontNeedEncoding.set('_');
     dontNeedEncoding.set('.');
     dontNeedEncoding.set('*');

     dfltEncName = AccessController.doPrivileged(
         new GetPropertyAction("file.encoding")
     );
 }

encode方法讲解

// 输入s , 编码enc
public static String encode(String s, String enc)
    throws UnsupportedEncodingException {

    // 标记是否需要转化
    boolean needToChange = false;
    // 将需要编码的字符串缓冲到StringBuffer
    StringBuffer out = new StringBuffer(s.length());
    Charset charset;
    CharArrayWriter charArrayWriter = new CharArrayWriter();

    // 抛出编码为空的异常
    if (enc == null)
        throw new NullPointerException("charsetName");

    try {
        // 设置编码
        charset = Charset.forName(enc);
    } catch (IllegalCharsetNameException e) {
        throw new UnsupportedEncodingException(enc);
    } catch (UnsupportedCharsetException e) {
        throw new UnsupportedEncodingException(enc);
    }

    for (int i = 0; i < s.length();) {
        int c = (int) s.charAt(i);
        // 是否在设置的字符集里面
        if (dontNeedEncoding.get(c)) {
            // 空格设置为+,其他的不变
            if (c == ' ') {
                c = '+';
                needToChange = true;
            }
            out.append((char)c);
            i++;
        } else {
            // 当出现不在字符集里的字符,开始遍历,将不在字符集里的字符加到charArrayWriter,直到出现在字符里的字符时停止遍历
            do {
                charArrayWriter.write(c);

                if (c >= 0xD800 && c <= 0xDBFF) {
                    if ( (i+1) < s.length()) {
                        int d = (int) s.charAt(i+1);
                        // utf-16的高位区
                        if (d >= 0xDC00 && d <= 0xDFFF) {

                            charArrayWriter.write(d);
                            i++;
                        }
                    }
                }
                i++;
            } while (i < s.length() && !dontNeedEncoding.get((c = (int) s.charAt(i))));
            // 清空charArrayWriter的内容
            charArrayWriter.flush();
            String str = new String(charArrayWriter.toCharArray());
            // 获取字节数组
            byte[] ba = str.getBytes(charset);
            // 遍历数组,将编码后的字符加到out中,其中caseDiff是大小写字符的距离('a' - 'A')
            for (int j = 0; j < ba.length; j++) {
                out.append('%');
                char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
                // converting to use uppercase letter as part of
                // the hex value if ch is a letter.
                if (Character.isLetter(ch)) {
                    ch -= caseDiff;
                }
                out.append(ch);
                ch = Character.forDigit(ba[j] & 0xF, 16);
                if (Character.isLetter(ch)) {
                    ch -= caseDiff;
                }
                out.append(ch);
            }
            charArrayWriter.reset();
            needToChange = true;
        }
    }
    // 如果转化过,则输出out,否则输出原来的字符串即可
    return (needToChange? out.toString() : s);
}

猜你喜欢

转载自blog.csdn.net/u013075699/article/details/78973586
今日推荐