这个是我做Android以来碰到的最烦的东西,该死的emoji表情,恨之入骨。。无奈这个问题分配给我了。我也只能硬着头皮做。

0.吐个槽先

首先,你要明白什么是emoji表情,不知道的google,不需要支持emoji的可以绕道了。

emoji有很多不同的版本,我tm最讨厌的就是不同版本的了。Unified DoCoMo KDDI Softbank Google

因为ios5升级了,emoji编码从softbank变成unified了。所以只能Android这边改了。伤心。

我要做的工作就是把消息中含有的unified的emoji编码过滤出来,然后映射出对应的表情资源显示出来。

1.准备工作。

google下emoji表情的历史,google code上有个源码,不过是java的,那么你要把它改成java的。。(记得当初解析gif表情时也是把java改成android,可怜的我为咩总是干这活。。)

这里有个link,上面有所有的编码对应转换。Emoji for PHP

然后google code里有所有对应的编码转换的xml。叫emoji4unicode.xml. 这里是link: emoji4unicode

如果没兴趣我等下会直接贴代码的,但是最好你先自己弄明白解析的原理是什么,emoji表情一直在增加,以后要兼容你就得自己想办法了。

2.举个例子

black sun with rays unified : U+2600 softbank: U+E04A

如果以前你解析过softbank,应该很熟悉了。好歹它还有个大致得顺序,解析得时候只要判断是否在这个unicode范围内就可以了。so easy

可是unified完全是无顺序得,所以必须得自己建好映射。

因为原始的emoji.xml很大,把所有的描述信息都放里面了,我不需要,所以我写了个java把xml解析了一遍,然后重新生成了一个我需要的xml。贴个图出来大家看下。

you see , 这个原始的xml实在太大了,有162K,而且还是xml解析。。你想想多耗内存和时间。所以必须把它再转换一遍。

so 这个过程做好了,就可以进行下一步真正的解析了。。

3 解析过程。

因为emoji是有表情分组的,所以你要优先考虑解析出来的也是分好组的。

HashMap<String, ArrayList<String>> emoMap = new HashMap<String, ArrayList<String>>();

我是这么来分组的。

解析xml,然后把2600这样的字符串转换成unicode。这个很关键,映射对应不上肯定也解析不出来。要注意的一点是有的emoji是两个unicode组成的  U+1F1F0 U+1F1F7  这样。。所以么。又多了一个环节。

HashMap<List<Integer>, String> convertMap = new HashMap<List<Integer>, String>();

再定义一个map来存unicode和string字符的映射。

if (xmlpull.getName().equals("e")) {
fromAttr = xmlpull.nextText();
emos.add(fromAttr);
List<Integer> fromCodePoints = new ArrayList<Integer>();
if (fromAttr.length() > ) {
String[] froms = fromAttr.split("\\_");
for (String part : froms) {
fromCodePoints.add(Integer.parseInt(part, ));
}
} else {
fromCodePoints.add(Integer.parseInt(fromAttr, ));
}
convertMap.put(fromCodePoints, fromAttr);
}

这样就把整个解析都写到内存里了。这个就做成单例咯,在程序一进来,application里初始化。

4,解析过程

这里我是把emoji表情解析出来,再改成[e]2600[/e]的形式。然后再用正则再解析一遍(为什么这样做。。因为消息里面不可能只有emoji表情的啊亲。。。你还要解析另外的表情。)

下面是过滤emoji表情的方法:

public String parseEmoji(String input) {
if (input == null || input.length() <= ) {
return "";
}
StringBuilder result = new StringBuilder();
int[] codePoints = toCodePointArray(input);
List<Integer> key = null;
for (int i = ; i < codePoints.length; i++) {
key = new ArrayList<Integer>()
if (i + < codePoints.length) {
key.add(codePoints[i]);
key.add(codePoints[i + ]);
if (convertMap.containsKey(key)) {
String value = convertMap.get(key);
if (value != null) {
result.append("[e]" + value + "[/e]");
}
i++;
continue;
}
}
key.clear();
key.add(codePoints[i]);
if (convertMap.containsKey(key)) {
String value = convertMap.get(key);
if (value != null) {
result.append("[e]" + value + "[/e]");
}
continue;
}
result.append(Character.toChars(codePoints[i]));
}
return result.toString();
}

看到这里,你可能觉得懵了。当时我也是卡了两三天,不停的网上找资料,反编译别人的代码。最后才找的解决方案的,代码其实没有很多,最重要的是要怎么去思考。

4.渲染成图片。

public static SpannableStringBuilder convetToHtml(String content, Context mContext) {
String regex = "\\[e\\](.*?)\\[/e\\]";
Pattern pattern = Pattern.compile(regex);
String emo = "";
Resources resources = mContext.getResources();
String unicode = EmojiParser.getInstance(mContext).parseEmoji(content);
Matcher matcher = pattern.matcher(unicode);
SpannableStringBuilder sBuilder = new SpannableStringBuilder(unicode);
Drawable drawable = null;
ImageSpan span = null;
while (matcher.find()) {
emo = matcher.group();
try {
int id = resources.getIdentifier(
"emoji_" + emo.substring(emo.indexOf("]") + , emo.lastIndexOf("[")),
"drawable", "package");
if (id != ) {
drawable = resources.getDrawable(id);
drawable.setBounds(, , , );
span = new ImageSpan(drawable);
sBuilder.setSpan(span, matcher.start(), matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} catch (Exception e) {
break;
}
}
return sBuilder;
}

好了,成功解析出来了。但是!!你得先把图片弄到手啊,亲。而且还要我这个格式得。

贴个图

额,话说这个我也是写了个java,把之前得softbank得命名转换成unified的命名,当初我还准备一个一个手动改来着,还好我同事一语点醒梦中人额。。不然我估计就吐血身亡了。程序写多了就是这样,思维固定了。。。

5.发emoji消息。

既然能显示了,你还得发啊,亲。

直接贴代码把,一个还原过程

public static String convertToMsg(CharSequence cs, Context mContext) {
SpannableStringBuilder ssb = new SpannableStringBuilder(cs);
ImageSpan[] spans = ssb.getSpans(, cs.length(), ImageSpan.class);
for (int i = ; i < spans.length; i++) {
ImageSpan span = spans[i];
String c = span.getSource();
int a = ssb.getSpanStart(span);
int b = ssb.getSpanEnd(span);
if (c.contains("emoji")) {
ssb.replace(a, b, convertUnicode(c));
}
}
ssb.clearSpans();
return ssb.toString();
}
private static String convertUnicode(String emo) {
emo = emo.substring(emo.indexOf("_") + );
if (emo.length() < ) {
return new String(Character.toChars(Integer.parseInt(emo, )));
}
String[] emos = emo.split("_");
char[] char0 = Character.toChars(Integer.parseInt(emos[], ));
char[] char1 = Character.toChars(Integer.parseInt(emos[], ));
char[] emoji = new char[char0.length + char1.length];
for (int i = ; i < char0.length; i++) {
emoji[i] = char0[i];
}
for (int i = char0.length; i < emoji.length; i++) {
emoji[i] = char1[i - char0.length];
}
return new String(emoji);
}

由于时间跨度比较长了。年初得时候写得,基本都记不清了。所以尽量不要来问我额,亲们,我只提供解决方案。

代码我也会上传一份,有需要得可以拿去耍。

最新文章

  1. js获取浏览器前缀
  2. css background-size
  3. selenium实战-自动退百度云共享群
  4. Unity 2D Sprite Lighting
  5. [dts]Device Tree机制
  6. 快钱报错:javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name解决
  7. php 5.3+ 连接mssql
  8. JSP-标准动作标记
  9. Java - 泛型 ( Generic )
  10. gameUnity 0.15 beta 网络游戏框架
  11. java thread yield 的设计目的是什么?
  12. hibernate 调用存储过程返回参数
  13. matlab-逻辑回归二分类(Logistic Regression)
  14. Django+xadmin的安装与配置
  15. 代码文档生成工具Doxygen的使用备忘
  16. Python之父:为什么操作符很有用?
  17. [转]BTC RPC API GetTransaction
  18. linux下编译安装pthreads扩展
  19. inotifywait实现目录监控--http://man.linuxde.net/inotifywait
  20. [转帖] k8s kubectl 命令行技巧

热门文章

  1. Oracle利用数据泵迁移用户
  2. php将数据库导出成excel的方法
  3. 内存管理、ARC
  4. Net Core开源通讯组件 SmartRoute
  5. Notes of the scrum meeting(10/30)
  6. iOS10.0 TabBar Bug(底部同时展示原生和自定义tabBar)-b
  7. arm-none-eabi-gcc,makefile,stm官方库构建stm32f4xx工程
  8. NeatUpload 同时选择并上传多个文件
  9. linux进程管理之服务
  10. NYOJ-469 擅长排列的小明 II AC 分类: NYOJ 2014-01-02 22:19 159人阅读 评论(0) 收藏