• 一段网上java常见escape和unescape方法的BUG


    escape编码和unescape编码,就是将一个字符转换为16进制unicode编码,前面加%字符进行标识。

    此处不再多做解释,参考这里:http://www.jb51.net/article/23657.htm。

    原本是js的一个方法,后来被转成java方法。具体参考这里 http://blog.sina.com.cn/s/blog_4bb52a160100d9tm.html ,是被程序员们copy和paste最多的通用代码。

    先看一下escape源码:

    /**
    * 实现js前台的escape()函数
    *
    * @param src
    * @return
    */
    public static String escape(String src) {
    int i;
    char j;
    StringBuffer tmp = new StringBuffer();
    tmp.ensureCapacity(src.length() * 6);
    for (i = 0; i < src.length(); i++) {
    j = src.charAt(i);--字符转换为int值
    if (Character.isDigit(j) || Character.isLowerCase(j) || Character.isUpperCase(j))
    tmp.append(j);--1.如果是数字或者字母,直接使用
    else if (j < 256) {
    tmp.append("%");--2.如果在[16-255],则加%前缀
    if (j < 16)
    tmp.append("0");--3.如果字符编码<16,则前面加%0前缀,(补0以使编码2个字符宽度)
    tmp.append(Integer.toString(j, 16));
    } else {
    tmp.append("%u");
    tmp.append(Integer.toString(j, 16));--4.其他编码全部以%u为前缀
            }
    }
    return tmp.toString();
    }

    再看一下unescap方法:

    public static String unescape(String src) {
    StringBuffer tmp = new StringBuffer();
    tmp.ensureCapacity(src.length());
    int lastPos = 0, pos = 0;
    char ch;
    while (lastPos < src.length()) {
    pos = src.indexOf("%", lastPos);--查%号
    if (pos == lastPos) {
    if (src.charAt(pos + 1) == 'u') {
    ch = (char) Integer.parseInt(src.substring(pos + 2, pos + 6), 16);//5--遇到%u,则读取后面的4个宽度字符,进行解码
                    tmp.append(ch);
    lastPos = pos + 6;
    } else {
    ch = (char) Integer.parseInt(src.substring(pos + 1, pos + 3), 16);//6--其他%,则读取2个宽度[0-255]的十六进展编码,进行解码
    tmp.append(ch);
    lastPos = pos + 3;
    }
    } else {
    if (pos == -1) {
    tmp.append(src.substring(lastPos));
    lastPos = src.length();
    } else {
    tmp.append(src.substring(lastPos, pos));
    lastPos = pos;
    }
    }
    }
    return tmp.toString();
    }

    代码逻辑很简单,分别解析了2宽度[0-255]和4宽度[4096-65535]的字符。

    可是有2个问题:3宽度[256-4095]的字符存不存在?4字符以上的宽度存不存在?如果存在,这段代码就存在严重BUG,会导致解析失败。

    先说第一个问题:

    东亚语言及大部分语言unicode编码转换为16进制后都占4个宽度,但并不意味3宽度字符不存在。比如百度百科瑜伽的印第安语:योग,3个字符,转换16进制后分别占3个宽度。%u92f%u94b%u917,对此类字符上述代码就会unescape失败。

    解决办法保证生成的>255的字符编码,有4个宽度。

    红色注释4处的代码修改为:

    if(j<4096){
        tmp.append(0)
    }
    tmp.append(Integer.toString(j, 16));--4.其他编码全部以%u为前缀

    或者

    tmp.append(String.format("%04x",j))

    第二个问题:

    十六进制4宽度代表2个字节。目前unicode的规范是ucs-2,即所有字符都以双字节存储。所以代码是可以搞定的。如果后续升级到ucs-4,甚至ucs-8,这段代码就肯定有问题了。不过,那应该是N年以后的事情了。ucs-2足以满足当前大部分场景。

  • 相关阅读:
    郝小亮-读王坚《在线》:互联网能做的和没做的事还有很多
    区块链的模型架构浅分析
    Springboot Application 集成 OSGI 框架开发
    java的OSGi确实是个坑
    所有围绕微信公众号,企业号开发者的企业或个人的创造的利润以及生存时间周期
    4张图让你看懂分布式架构从硬件到软件
    .NET J2EE APP全局会话架构运用场景
    ilspy导致c# dll代码被窃取
    windows+pytorch+pycharm配置
    海康-qt+opencv开发海康威视网络摄像机采集处理程序
  • 原文地址:https://www.cnblogs.com/songxinya/p/4735888.html
Copyright © 2020-2023  润新知