emoji表情是啥就不具体介绍了,主要记住一点就是emoji是使用4字节来表示的,具体的unicode码可以查看这里,所以在显示存储的时候就跟普通的字符大有不同。
项目中原先没有考虑到emoji表情的存在,导致问题的出现,在存储时,使用的字符编码集就是utf-8编码,utf-8编码虽然是使用1-6个变长子节表示的,但是在mysql中是使用3子节表示的,刚好没发表示emoji表情,处理方法最简单的当然是修改mysql的配置,utf-8改为utf-8mb4编码,当然表的字符编码,数据库连接的编码都需要修改,但是线上的数据库修改比较麻烦,风险较大,这种方法应该在设计初比较适合,但是中后期不适合,pass。
然后就是不考虑emoji表情,直接删除掉,很简单,直接使用正则表达式,匹配替换,在网上找了几个代码,都是可以使用的,
public static function remove_emoji($text){ //直接去除
return preg_replace('/([0-9|#][\x{20E3}])|[\x{00ae}|\x{00a9}|\x{203C}|\x{2047}|\x{2048}|\x{2049}|\x{3030}|\x{303D}|\x{2139}|\x{2122}|\x{3297}|\x{3299}][\x{FE00}-\x{FEFF}]?|[\x{2190}-\x{21FF}][\x{FE00}-\x{FEFF}]?|[\x{2300}-\x{23FF}][\x{FE00}-\x{FEFF}]?|[\x{2460}-\x{24FF}][\x{FE00}-\x{FEFF}]?|[\x{25A0}-\x{25FF}][\x{FE00}-\x{FEFF}]?|[\x{2600}-\x{27BF}][\x{FE00}-\x{FEFF}]?|[\x{2900}-\x{297F}][\x{FE00}-\x{FEFF}]?|[\x{2B00}-\x{2BF0}][\x{FE00}-\x{FEFF}]?|[\x{1F000}-\x{1F6FF}][\x{FE00}-\x{FEFF}]?/u', '', $text);
}
public static function emojiFilter($text){ //直接去除
$text = json_encode($text);
preg_match_all("/(\\\\ud83c\\\\u[0-9a-f]{4})|(\\\\ud83d\\\u[0-9a-f]{4})|(\\\\u[0-9a-f]{4})/", $text, $matchs);
if(!isset($matchs[0][0])) { return json_decode($text, true); }
$emoji = $matchs[0];
foreach($emoji as $ec) {
$hex = substr($ec, -4);
if(strlen($ec)==6) {
if($hex>='2600' and $hex<='27ff') {
$text = str_replace($ec, '', $text);
}
} else {
if($hex>='dc00' and $hex<='dfff') {
$text = str_replace($ec, '', $text);
}
}
}
return json_decode($text, true);
}
public static function re($somestr){ //直接去除
$some_string = preg_replace('/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]'.
'|[\x00-\x7F][\x80-\xBF]+'.
'|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*'.
'|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})'.
'|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
'?', $somestr );
//reject overly long 3 byte sequences and UTF-16 surrogates and replace with ?
$some_string = preg_replace('/\xE0[\x80-\x9F][\x80-\xBF]'.
'|\xED[\xA0-\xBF][\x80-\xBF]/S','?', $some_string );
return $some_string;
}
项目中使用的是php语言,所以找到几个都是php的代码,其它语言也是类似的。
考虑到信息丢失等问题,可以借鉴以上的方法,使用正则表达式,给相应的emoji表情编码做标记,传输的时候再去除这些标签,就可以解决了。搜索了下,参考这里,提出下面的代码:
public static function conver($content){ //第三方标记
$length = mb_strlen($content,'utf-8');
for ($i=0; $i < $length; $i++) {
$_tmpStr = mb_substr($content,$i,1,'utf-8');
if(strlen($_tmpStr) >= 4){
$strEncode .= '[[EMOJI:'.base64_encode($_tmpStr).']]';
}else{
$strEncode .= $_tmpStr;
}
}
return $strEncode;
}
public static function back($content){ ////第三方标记去除
$callback = array('Tool_Emoji', 'rawurl');
$res = preg_replace_callback("/\[\[EMOJI:(.*?)\]\]/", $callback, $content);
return $res;
/* $text = preg_replace_callback("/\[\[EMOJI:(.*?)\]\]/", function($matches){
return rawurldecode($matches[1]); //php版本问题,无法直接使用
}, $content);
return $text; */
}
public static function rawurl($matches){
return base64_decode($matches[1]);
}
这里和参考页不一样的地方在于编码的方式不同,使用base64进行编码可以节省空间,相应的数据行也会减小。
这里也贴出java对这个问题的解决代码,参考这里
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.UnsupportedEncodingException;
public class test{
public static void main(String[] args) throws Exception {
String content = args[0];
System.out.println(content);
int strLength = content.length();
String filterContent = emojiFilter(content);
System.out.println(filterContent);
String emojiStr = emojiRecovery(filterContent);
System.out.println(emojiStr);
}
private static String emojiFilter(String str){
String patternString = "([\\x{10000}-\\x{10ffff}\ud800-\udfff])";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(str);
StringBuffer sb = new StringBuffer();
while(matcher.find()) {
try {
matcher.appendReplacement(sb, "[[EMOJI:" + URLEncoder.encode(matcher.group(1),"UTF-8") + "]]");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
matcher.appendTail(sb);
return sb.toString();
}
private static String emojiRecovery(String str){
String patternString = "\\[\\[EMOJI:(.*?)\\]\\]";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(str);
StringBuffer sb = new StringBuffer();
while(matcher.find()) {
try {
matcher.appendReplacement(sb, URLDecoder.decode(matcher.group(1),"UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
matcher.appendTail(sb);
return sb.toString();
}
}
当然,公司内部也是有处理emoji的工具的,直接把相应的emoji表情替换为相应的图片地址,但是考虑到emoji表情的不断增多,工具更新的及时性,而且服务端与客户端展示的图片不一样,这里就不使用了。
ps:本人工作主要是为客户端提供相应的接口以展示数据。
这是好久之前的项目了,蹭着中秋假期回顾纪录下,免得忘记。
来源:oschina
链接:https://my.oschina.net/u/551527/blog/747206