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 。修改语句如下:
ALTER TABLE table_name MODIFY COLUMN content varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'content of message';在某种业务情景下,我们可以选择过滤掉这种“非法”的字符。我采用的方式是,在字符上面做操作,下面是Java示例代码,核心的代码附上,应该是 无法直接下载就能够编译,你得小小的做一些微调,没有额外的依赖:
public class EmojiFilter { /** * 检测是否有emoji字符 * @param source * @return 一旦含有就抛出 */ public static boolean containsEmoji(String source) { if (StringUtils.isBlank(source)) { return false; } int len = source.length(); for (int i = 0; i < len; i++) { char codePoint = source.charAt(i); if (isEmojiCharacter(codePoint)) { //do nothing,判断到了这里表明,确认有表情字符 return true; } } return false; } private static boolean isEmojiCharacter(char codePoint) { return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA) || (codePoint == 0xD) || ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF)); } /** * 过滤emoji 或者 其他非文字类型的字符 * @param source * @return */ public static String filterEmoji(String source) { if (!containsEmoji(source)) { return source;//如果不包含,直接返回 } //到这里铁定包含 StringBuilder buf = null; int len = source.length(); for (int i = 0; i < len; i++) { char codePoint = source.charAt(i); if (isEmojiCharacter(codePoint)) { if (buf == null) { buf = new StringBuilder(source.length()); } buf.append(codePoint); } else { } } if (buf == null) { return source;//如果没有找到 emoji表情,则返回源字符串 } else { if (buf.length() == len) {//这里的意义在于尽可能少的toString,因为会重新生成字符串 buf = null; return source; } else { return buf.toString(); } } } }
还有优化的空间,但是已经能够满足大多数情况的需求,附上单元测试(JUnit4):
public class EmojiFilterTest { /** * 测试emoji表情 */ @Test public void fileterEmoji() { String s = "<body>口口213这是一个有各种内容的消息, Hia Hia Hia !!!! xxxx@@@...*)!" + "(@*$&@(&#!)@*)!&$!)@^%@(!&#. 口口口], "; String c = Utils.filterEmoji(s); assertFalse(s.equals(c)); String expected = "<body>213这是一个有各种内容的消息, Hia Hia Hia !!!! xxxx@@@...*)" + "!(@*$&@(&#!)@*)!&$!)@^%@(!&#. ], "; assertEquals(expected, c); // assertSame(c, expected); assertSame(expected, "<body>213这是一个有各种内容的消息, Hia Hia Hia !!!! xxxx@@@...*)" + "!(@*$&@(&#!)@*)!&$!)@^%@(!&#. ], "); assertSame(c, Utils.filterEmoji(c)); } }
原文链接:http://doombyte.com/blog/2013/03/20/filter-emoji-emotion-in-string/
能不坑人么?
isEmojiCharacter这个方法名和方法内容不符合,容易引起误会。filterEmoji方法下面要加source=""+source;return的时候要trim(),否则无法判断单单独表情字符屁用也不管一条
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。