zoukankan      html  css  js  c++  java
  • Unified Emoji表情for Android

    这个是我做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() > 6) {
      String[] froms = fromAttr.split("\_");
      for (String part : froms) {
        fromCodePoints.add(Integer.parseInt(part, 16));
      }
      } else {
        fromCodePoints.add(Integer.parseInt(fromAttr, 16));
    }
      convertMap.put(fromCodePoints, fromAttr);
    }

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

    4,解析过程

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

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

    public String parseEmoji(String input) {
    if (input == null || input.length() <= 0) {
      return "";
    }
    StringBuilder result = new StringBuilder();
    int[] codePoints = toCodePointArray(input);
    List<Integer> key = null;
    for (int i = 0; i < codePoints.length; i++) {
      key = new ArrayList<Integer>()
        if (i + 1 < codePoints.length) {
          key.add(codePoints[i]);
          key.add(codePoints[i + 1]);
        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();
    }

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

    贴个图

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

    5.发emoji消息。

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

    public static String convertToMsg(CharSequence cs, Context mContext) {
    SpannableStringBuilder ssb = new SpannableStringBuilder(cs);
    ImageSpan[] spans = ssb.getSpans(0, cs.length(), ImageSpan.class);
    for (int i = 0; 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("_") + 1);
    if (emo.length() < 6) {
    return new String(Character.toChars(Integer.parseInt(emo, 16)));
    }
    String[] emos = emo.split("_");
    char[] char0 = Character.toChars(Integer.parseInt(emos[0], 16));
    char[] char1 = Character.toChars(Integer.parseInt(emos[1], 16));
    char[] emoji = new char[char0.length + char1.length];
    for (int i = 0; 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);
    }

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

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

    源代码:http://stay4it.com/course/20

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

  • 相关阅读:
    原生js ajax与jquery ajax的区别
    ajax的五大步骤
    js中setTimeout()时间参数设置为0的探讨
    js数组与字符串的相互转换方法
    javascript的三个组成部分
    linq 获取不重复数据,重复数据 var unique = arr.GroupBy(o => o).Where(g => g.Count() == 1) .Select(g => g.ElementAt(0));
    C# 随机 抽奖 50个随机码 不重复
    聚集索引和非聚集索引 聚集索引的叶节点就是最终的数据节点,而非聚集索引的叶节仍然是索引节点,但它有一个指向最终数据的指针。
    WPF ControlTemplate,DataTemplate
    C# 实现 奇数偶数排序,奇数在前,偶数在后
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/5913401.html
Copyright © 2011-2022 走看看