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足以满足当前大部分场景。

一段网上java常见escape和unescape方法的BUG的更多相关文章

  1. Java常见序列化与反序列方法总结

    很多商业项目用到数据库.内存映射文件和普通文件来完成项目中的序列化处理的需求,但是这些方法很少会依靠于Java序列化.本文也不是用来解释序列化的,而是一起来看看面试中有关序列化的问题,这些问题你很有可 ...

  2. javascript中escape()、unescape()、encodeURI()、encodeURIComponent()、decodeURI()、decodeURIComponent()比较

    这些URI方法encodeURI.encodeURIComponent().decodeURI().decodeURIComponent()代替了BOM的escape()和unescape()方法.U ...

  3. java实现js端的escape和unescape

    1.今天遇到这么个问题,需要把一些特殊字符传递到后台进行处理,例如Aa111111!@#,结果到了后台出现了个别字符中文符号了.这个时候需要转码.常见的就是js端的escape和unescape这种函 ...

  4. EscapeAndUnescapeUtil【java模拟js的escape和unescape函数】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 在这里做一个记录,基本代码同参考资料<java模拟js的escape和unescape函数>一样. 效果图     代码 ...

  5. Java常见的几种内存溢出及解决方法

    Java常见的几种内存溢出及解决方法[情况一]:java.lang.OutOfMemoryError:Javaheapspace:这种是java堆内存不够,一个原因是真不够(如递归的层数太多等),另一 ...

  6. java常见异常集锦

    1. java.lang.nullpointerexception 这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用了未经初始化的对象或者是不存在的对 ...

  7. Java常见开发规范

    1 背景概述 作为程序员大军中的一员,笔者工作于沈阳数通畅联软件技术有限公司.在任职工作的第一天就听领导强调开发规范的重要性,但是笔者心里还想为什么开发规范是最重要的,难道是不应该是实现功能就万事大吉 ...

  8. java 常见的异常大集合

    算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 类型强制转换异常:ClassCastException 数组负下标异常:NegativeAr ...

  9. 【面试笔试】Java常见面试笔试总结

    Java 基础 1.有哪些数据类型 Java定义了8种简单类型:byte.short.int.long.char.float.double和boolean. 2.面向对象的语言特征 封装.继承.多态 ...

随机推荐

  1. spring setter方法注入

    <bean id="dao" class="Dao"></bean> <bean id="service" c ...

  2. xp 下卸载 硬盘安装的 ubuntu (本人的悲伤史)

    正常启动XP系统,到http://www.sysint.no 下载 MBRFIX.zip,解压,把文件放在C盘, 点击“开始”==“运行”==“cmd”,出现下面图 输入cd\,如下图, 再按回车键, ...

  3. jquery右下角返回顶部

    实现的效果也就是,当有滚动条是,滚动条未动或与顶部距离小于多少像素是,返回顶部按钮处于隐身状态,当滚动条与顶部距离大于一定像素时,返回顶部按钮出现,实现点击‘返回按钮’后,从当前位置回到等不位置.要先 ...

  4. (转载)与OpenDialog相关的一个问题

    OpenDialog的一个问题 有一个功能要求就是[每次打开文件的对话框的默认路径是上一次保存文件的路径],本来这个就是设置OpenDialog控件的InitialDir属性就行了,但是第一次打开的时 ...

  5. Python全栈开发之MySQL(二)------navicate和python操作MySQL

    一:Navicate的安装 1.什么是navicate? Navicat是一套快速.可靠并价格相宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设.它的设计符合数据库管理员.开发人员及中小 ...

  6. C++库编译

    C++库编译 1. POCO编译 进入源文件目录,选择相应的VS版本进行编译(build_vs140).    设置系统环境变量: POCO_BASE 2. Boost编译 ####简单编译    在 ...

  7. 缓存 Cache

    Controllers层 public class HomeController : Controller    {        //        // GET: /Home/       // ...

  8. android SurfaceView绘制 重新学习--控制动画移动

    直接上demo,图是自己切的,将就用吧.点击左右两边分别向左右移动. public class MySurfaceView extends SurfaceView implements Callbac ...

  9. XSS解决方案系列之四:关于编码

    本文准备说明以下几个问题: 1. 关于重复编码的问题 2. 关于编码的多种形式的问题 3. 关于编码的几个常见问题 [说明] 本文所述编码是指encode,可以理解为转义,而不是编程序写代码. 编码或 ...

  10. Android LogCat 日志记录

    日志级别列表如下(从低到高): V — Verbose (lowest priority) D — Debug I — Info W — Warning E — Error F — Fatal S — ...