数据库中的不可见字符

场景:产品经理通过后台系统插入一个字母组成的优惠码(例如:coupon)之后,再从后台通过关键字coupon去查找这个优惠码,查不到,同时影响线上使用。

 

假设表名:exchange_code.

假设列名:code , varchar类型

 

症状1:通过Sequel Pro按字段名等等条件搜索coupon,搜索不出来这条记录。

等价于SQL: SELECT  * from exchange_cdoe where code = 'coupon';

 

 

症状2:通过contains条件搜索,能找到这条记录。

等价于SQL: SELECT  * from exchange_cdoe where code contains 'coupon';

 

 

症状3:通过 length 函数,计算一下code 长度, 发现长度并不等于coupon的长度6.

 

 

看上去是6个字母,却表现出上面的情况。

 

后面团队想到办法,把里面的内容复制出来,转化为 unicode。

发现了里面包含 unicode \200b 这个不可见字符。



 

coupon​

http://tool.chinaz.com/tools/unicode.aspx  (从左至右复制上面这一行字符,去这个网址转换unicode试试)

 

问题复现

利用java 复现问题

    @Test
    public void testBlog(){
        // 字母m  对应unicode u6d
        String unicode = "\\u6d\\u200b\\u6d";
        System.out.println("unicode:"+unicode);
        String string = unicode2String(unicode) ;
        System.out.println("string:"+string);
    }

    /**
     * unicode 转字符串
     */
    public static String unicode2String(String unicode) {

        StringBuffer string = new StringBuffer();

        String[] hex = unicode.split("\\\\u");

        for (int i = 1; i < hex.length; i++) {

            // 转换出每一个代码点
            int data = Integer.parseInt(hex[i], 16);

            // 追加成string
            string.append((char) data);
        }

        return string.toString();
    }

输出结果

unicode:\u6d\u200b\u6d

string:m​m

 

输出结果中mm之间有一个不可见不占位的 \u200b 特殊字符,类似的 \u200c 也是一样的效果。

这些字符的产生 也许是因为”实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。” — https://zh.wikipedia.org/wiki/Unicode 。

 

问题预防

通过正则表达式校验数据合法性(例如,只允许数字和大小写字母)。

    @Test
    public void testBlog(){
        // 字母m  对应unicode \\u6d
        String unicode = "\\u6d\\u200b\\u6d";
        System.out.println("unicode:"+unicode);
        String string = unicode2String(unicode) ;
        System.out.println("string:"+string);
        Pattern pattern = Pattern.compile("[a-zA-Z0-9.]+");
        System.out.println("pass? "+pattern.matcher(string).matches());
    }

 输出结果

unicode:\u6d\u200b\u6d

string:m​m

pass? false

 

 

=== 程序员日常小故事 之 隐形的字符===

产品W:“怎么回事啊,这条记录我刚插入的,后台怎么查不出来啊”

程序员T:“我看看怎么回事,之前都是好的啊”

产品H:“这个功能模块怎么又出问题了?”

程序员Z:“我看看啊,数据库里去查一下,怎么数据库里按字段查,也查不出来啊。 ”

某某程序员:“按ID查。”

某某程序员:“查一下这个字段的长度”

某某程序员:“奶奶的,怎么和看上去的长度不一样”

某某程序员:“看看字符串的unicode编码”

某某程序员:“复制到Java里面转成unicode看看”

某某程序员:“奶奶的怎么有不可见字符”

程序员T:“产品W,你是怎么输入不可见字符的…”

产品W:“我是正常操作的呀”

posted @ 2017-10-02 14:45  tanliwei  阅读(1894)  评论(0编辑  收藏  举报