过滤字符串中的Emoji表情

来源:互联网 发布:c51单片机中断程序 编辑:程序博客网 时间:2024/06/05 17:48

    iOS 5.0之前,苹果都是采用3个字节来承接 emoji 表情,Java 的普通 char 可以支持显示。但 iOS 5.0 之后, 苹果升级了系统自带的 emoji 表情输入法,用的 Unicode 6 标准来统一,是采用4个 bytes 来承接一个 emoji 表情。如果不做处理的话,这种表情直接存储到 mysql5.5 以下的数据库是会报错的。就像这两个表情一样:口口, 在 Windows 8 以下估计都不支持显示,可能会显示成框框,可能压根就是空白, 你可以在 Mac 中使用Safari 浏览器中,就可以看到。经过测试,在 Mac 就算用 Chrome 浏览器(Version 25.0.1364.172)也是不行的。

这种数据在 Mysql 5.5 之前,UTF-8 支持1-3个字节的编码,从 Mysql5.5 开始后,可以支持4个字节的 UTF 编码,但要特殊标记。修改 Mysql 相应存储字段为 utf8mb4 。修改语句如下: 

1ALTER TABLEtable_name
2  MODIFYCOLUMN content varchar(500)CHARACTER
3  SETutf8mb4 COLLATE utf8mb4_unicode_ci
4  DEFAULTNULL COMMENT 'content of message';
在某种业务情景下,我们可以选择过滤掉这种“非法”的字符。我采用的方式是,在字符上面做操作,下面是Java示例代码,核心的代码附上,应该是 无法直接下载就能够编译,你得小小的做一些微调,没有额外的依赖:
01public classEmojiFilter {
02 
03    /**
04     * 检测是否有emoji字符
05     * @param source
06     * @return 一旦含有就抛出
07     */
08    publicstatic boolean containsEmoji(String source) {
09        if(StringUtils.isBlank(source)) {
10            returnfalse;
11        }
12 
13        intlen = source.length();
14 
15        for(int i = 0; i < len; i++) {
16            charcodePoint = source.charAt(i);
17 
18            if(isEmojiCharacter(codePoint)) {
19                //do nothing,判断到了这里表明,确认有表情字符
20                returntrue;
21            }
22        }
23 
24        returnfalse;
25    }
26 
27    privatestatic boolean isEmojiCharacter(char codePoint) {
28        return(codePoint == 0x0) ||
29                (codePoint ==0x9) ||
30                (codePoint ==0xA) ||
31                (codePoint ==0xD) ||
32                ((codePoint >=0x20) && (codePoint <= 0xD7FF)) ||
33                ((codePoint >=0xE000) && (codePoint <= 0xFFFD)) ||
34                ((codePoint >=0x10000) && (codePoint <= 0x10FFFF));
35    }
36 
37    /**
38     * 过滤emoji 或者 其他非文字类型的字符
39     * @param source
40     * @return
41     */
42    publicstatic String filterEmoji(String source) {
43 
44        if(!containsEmoji(source)) {
45            returnsource;//如果不包含,直接返回
46        }
47        //到这里铁定包含
48        StringBuilder buf =null;
49 
50        intlen = source.length();
51 
52        for(int i = 0; i < len; i++) {
53            charcodePoint = source.charAt(i);
54 
55            if(isEmojiCharacter(codePoint)) {
56                if(buf == null) {
57                    buf =new StringBuilder(source.length());
58                }
59 
60                buf.append(codePoint);
61            }else {
62            }
63        }
64 
65        if(buf == null) {
66            returnsource;//如果没有找到 emoji表情,则返回源字符串
67        } else {
68            if(buf.length() == len) {//这里的意义在于尽可能少的toString,因为会重新生成字符串
69                buf =null;
70                returnsource;
71            }else {
72                returnbuf.toString();
73            }
74        }
75 
76    }
77}

还有优化的空间,但是已经能够满足大多数情况的需求,附上单元测试(JUnit4):

01public classEmojiFilterTest {
02 
03 
04 /**
05     * 测试emoji表情
06     */
07    @Test
08    publicvoid fileterEmoji() {
09        String s ="<body>口口213这是一个有各种内容的消息,  Hia Hia Hia !!!! xxxx@@@...*)!"+
10                "(@*$&@(&#!)@*)!&$!)@^%@(!&#. 口口口], ";
11        String c = Utils.filterEmoji(s);
12        assertFalse(s.equals(c));
13        String expected ="<body>213这是一个有各种内容的消息,  Hia Hia Hia !!!! xxxx@@@...*)"+
14                "!(@*$&@(&#!)@*)!&$!)@^%@(!&#. ], ";
15        assertEquals(expected, c);
16//        assertSame(c, expected);
17        assertSame(expected,"<body>213这是一个有各种内容的消息,  Hia Hia Hia !!!! xxxx@@@...*)"+
18                "!(@*$&@(&#!)@*)!&$!)@^%@(!&#. ], ");
19        assertSame(c, Utils.filterEmoji(c));
20    }
21 
22}

原文链接:http://doombyte.com/blog/2013/03/20/filter-emoji-emotion-in-string/


原创粉丝点击