Android对emoji表情的处理(二)

接上文 Android对emoji表情的处理

问题

之前一篇文章描述了,如何将android手机的emoji过滤掉,显示"/ufffd"(这个图标),可是人家又提问题了,说iphone手机显示的emoji数量和android机器上显示的不一致,不是1:1。

分析

在我个人看来,emoji有许多基础表情,都是用单个unicode进行编码的,比如 以下的
Android对emoji表情的处理(二)_第1张图片
可是有些表情是由基础表情复合而成的,比如 国旗类,本身Android识别这些表情时,也会显示成2个字母图片
Android对emoji表情的处理(二)_第2张图片
方框数字类本身就是由数字和方框图组成。
Android对emoji表情的处理(二)_第3张图片
比如职业类(最复杂), 女农民
Android对emoji表情的处理(二)_第4张图片
unicode是U + 1F469 U + 200D U + 1F33E
分别代表女+连接符+水稻
可以利用上篇讲到的string2Unicode方法,打印出来如下

\ud83d\udc69\u200d\ud83c\udf3e

在比如 最深色女农民
Android对emoji表情的处理(二)_第5张图片
unicode是U + 1F469 U + 1F3FF U + 200D U + 1F33E
增加了1个肤色参数

\ud83d\udc69\ud83c\udfff\u200d\ud83c\udf3e

再比如 最深色女警
Android对emoji表情的处理(二)_第6张图片
?U + 1F46E 警察(男)
?U + 1F3FF 最深色
U + 200D 连接符
♀U + 2640 女性
️U + FE0F 变化选择器

\ud83d\udc6e\ud83c\udfff\u200d\u2640\ufe0f

最容易的方法就是把所有表情添加到Matcher 中,找到后全部替换掉,但是表情太多,所以要找到一些规律,然后进行替换。

方法

为了不改变原来的思路,还是使用上篇的filterEmoji方法进行过滤,关键是找到过滤条件,这里用的是 正则表达式
单个表情过滤范围不变,多个表情需要找到规律进行过滤。

  1. 国旗类
    国旗类是由2个字母组成,所以过滤条件为
[\ud83c\udde6-\ud83c\uddff][\ud83c\udde6-\ud83c\uddff]
  1. 数字框类
    数字框是数字加框的组合
[\u0030-\u0039]\ufe0f\u20e3
  1. 职业类
    职业类是最麻烦的,除了包括最先的一个编码,后面还可能有肤色,性别,物品等;期间还有\u200d连接符进行连接,所以我打算把除了第一个编码,后面编码全部替换为空,然后再进行2次过滤,就可以实现1:1了,确定范围如下:
"([\ud83c\udc00-\ud83c\udfff]\u200d(?:[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\ud83e\udc00-\ud83e\udfff]))" +
  						"|([\ud83c\udffb-\ud83c\udfff]\u200d[\u2600-\uffff][\u2600-\uffff])" +
  						"|\u200d[\u2600-\uffff][\u2600-\uffff]"+
  						"|\u200d(?:[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\ud83e\udc00-\ud83e\udfff])"+
  						"|[\u2640-\u2642]|[\ud83c\udffb-\ud83c\udfff]"

最终代码

最终,可以将iphone手机端的所有emoji表情可以1:1的替换为\ufffd(不支持)表情,在Android机器上显示。
比如在进行MFI认证的时候,认证机构就会要求正常显示emoji或者1:1显示不支持表情。

public class FilterEmoji
{
  private static FilterEmoji filterEmoji = null;

  private FilterEmoji(Context context)
  {
  }

  public static FilterEmoji getInstance(Context context)
  {
  	if (filterEmoji == null)
  	{
  		filterEmoji = new FilterEmoji(context);
  	}
  	return filterEmoji;
  }

  public String filterEmoji(String source)
  {
  	Log.d("FilterEmoji","before source.len --> "+source.length());
  	if (source != null)
  	{
  		Pattern emoji1 = Pattern
  				.compile(
  						"([\ud83c\udc00-\ud83c\udfff]\u200d(?:[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\ud83e\udc00-\ud83e\udfff]))" +
//							"|([\ud83c\udc00-\ud83c\udfff]\u200d[\ud83d\udc00-\ud83d\udfff])" +
//							"|([\ud83c\udc00-\ud83c\udfff]\u200d[\ud83e\udc00-\ud83e\udfff])" +
  						"|([\ud83c\udffb-\ud83c\udfff]\u200d[\u2600-\uffff][\u2600-\uffff])" +
  						"|\u200d[\u2600-\uffff][\u2600-\uffff]"+
  						"|\u200d(?:[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\ud83e\udc00-\ud83e\udfff])"+
  						"|[\u2640-\u2642]|[\ud83c\udffb-\ud83c\udfff]",
  						Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
  		Matcher emojiMatcher1 = emoji1.matcher(source);
  		if (emojiMatcher1.find())
  		{
  			 String s = string2Unicode(source);
  			 Log.d("FilterEmoji","before unincode --> "+s);
  			// 空
  			source = emojiMatcher1.replaceAll("");
  			 String s1 = string2Unicode(source);
  			 Log.d("FilterEmoji","after1 unincode --> "+s1);
  		}
  		Log.d("FilterEmoji","after1 source.len --> "+source.length());
  		Pattern emoji = Pattern
  				.compile(
  						"([\ud83c\udde6-\ud83c\uddff][\ud83c\udde6-\ud83c\uddff])|([\u0030-\u0039]\ufe0f\u20e3)|[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\ud83e\udc00-\ud83e\udfff]|[\u2500-\u29ff]|[\u20d0-\u20e2]|[\u20e4-\u20f0]|[\u2b00-\u2bff]|[\u3297-\u3299]|[\u2300-\u23ff]|[\u2190-\u21ff]|[\u24b6-\u24e9]",
  						Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
  		Matcher emojiMatcher = emoji.matcher(source);
  		if (emojiMatcher.find())
  		{
  			 String s = string2Unicode(source);
  			 Log.d("FilterEmoji","unincode --> "+s);
  			// \ufffd
  			source = emojiMatcher.replaceAll("\ufffd");
  			String s2 = string2Unicode(source);
  			 Log.d("FilterEmoji","after2 unincode --> "+s2);
  			 return source;
  		}
  		Log.d("FilterEmoji","final after source.len --> "+source.length());
  		return source;
  	}
  	return source;
  }

  /**
   * 字符串转换unicode
   */
  public static String string2Unicode(String string)
  {

  	StringBuffer unicode = new StringBuffer();

  	for (int i = 0; i < string.length(); i++)
  	{

  		// 取出每一个字符
  		char c = string.charAt(i);

  		// 转换为unicode
  		unicode.append("\\u" + Integer.toHexString(c));
  	}

  	return unicode.toString();
  }
}

警告

如果是过滤列表的所有文字,因为比较比较耗时,可能会导致滑动列表卡顿,建议不要长期使用。

一些emoji的转化码

CN  \ud83c\udde8\ud83c\uddf3   U+1F1E8 U+1F1F3
A  U+1F1E6  \ud83c\udde6
Z  U+1F1FF   \ud83c\uddff

3kaung  \u33\ufe0f\u20e3
0 \u30\ufe0f\u20e3 U+0030 U+20E0

女警颜色性别  \ud83d\udc6e\ud83c\udfff\u200d\u2640\ufe0f

女警\ud83d\udc6e

性别女 \u2640

皮肤黑5 \ud83c\udfff  1F3FF

黑4 \ud83c\udffe

黑1 \ud83c\udffb

男警黑4\ud83d\udc6e\ud83c\udffe

工人皮肤女\ud83d\udc77\ud83c\udfff\u200d\u2640\ufe0f

长帽皮肤女\ud83d\udc82\ud83c\udfff\u200d\u2640\ufe0f
侦探

\ud83d\udc69\ud83c\udfff\u200d\u2695\ufe0f  女医生
\ud83d\udc69\ud83c\udfff\u200d\ud83c\udf3e  女农民
\ud83d\udc69\ud83c\udfff\u200d\ud83c\udf73  女厨师
\ud83d\udc69\ud83c\udfff\u200d\ud83c\udf93  女博士
\ud83d\udc69\ud83c\udfff\u200d\ud83c\udfa4  女歌手

\ud83d\udc69\u200d\ud83d\udcbc  女包  女白领
\ud83d\udc69\ud83c\udffb\u200d\ud83d\udcbc


连接 u200d  ufe0f

你可能感兴趣的:(emoji)