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 。修改语句如下:
2 | MODIFY COLUMN content varchar (500) CHARACTER |
3 | SET utf8mb4 COLLATE utf8mb4_unicode_ci |
4 | DEFAULT NULL COMMENT 'content of message' ; |
在某种业务情景下,我们可以选择过滤掉这种“非法”的字符。我采用的方式是,在字符上面做操作,下面是Java示例代码,核心的代码附上,应该是 无法直接下载就能够编译,你得小小的做一些微调,没有额外的依赖:
01 | public class EmojiFilter { |
08 | public static boolean containsEmoji(String source) { |
09 | if (StringUtils.isBlank(source)) { |
13 | int len = source.length(); |
15 | for ( int i = 0 ; i < len; i++) { |
16 | char codePoint = source.charAt(i); |
18 | if (isEmojiCharacter(codePoint)) { |
27 | private static boolean isEmojiCharacter( char codePoint) { |
28 | return (codePoint == 0x0 ) || |
32 | ((codePoint >= 0x20 ) && (codePoint <= 0xD7FF )) || |
33 | ((codePoint >= 0xE000 ) && (codePoint <= 0xFFFD )) || |
34 | ((codePoint >= 0x10000 ) && (codePoint <= 0x10FFFF )); |
38 | * 过滤emoji 或者 其他非文字类型的字符 |
42 | public static String filterEmoji(String source) { |
44 | if (!containsEmoji(source)) { |
48 | StringBuilder buf = null ; |
50 | int len = source.length(); |
52 | for ( int i = 0 ; i < len; i++) { |
53 | char codePoint = source.charAt(i); |
55 | if (isEmojiCharacter(codePoint)) { |
57 | buf = new StringBuilder(source.length()); |
60 | buf.append(codePoint); |
68 | if (buf.length() == len) { |
72 | return buf.toString(); |
还有优化的空间,但是已经能够满足大多数情况的需求,附上单元测试(JUnit4):
01 | public class EmojiFilterTest { |
08 | public void 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); |
17 | assertSame(expected, "<body>213这是一个有各种内容的消息, Hia Hia Hia !!!! xxxx@@@...*)" + |
18 | "!(@*$&@(&#!)@*)!&$!)@^%@(!&#. ], " ); |
19 | assertSame(c, Utils.filterEmoji(c)); |
原文链接:http://doombyte.com/blog/2013/03/20/filter-emoji-emotion-in-string/