最新emoji表情代码大全_NO.3 如何用Emoji迷惑人类

如何用

1️⃣🐴🐔

迷惑人类

03

af0e52daf03d53bebb8590a858732f26.png

    Emoji,是维达勋爵,或者说是安纳金·天行者发明的。当年勋爵的部下急于寻找绝地武士的踪迹,几乎把整个舰队都送进了共和国的埋伏圈。面具下的维达勋爵对属下感到极度的无奈,在沉重的呼吸声中,他叹息道:诶,莫急。一旁的侍卫把这话记录了下来,史称诶莫急,也就是Emoji之始。

    不过,低能的帝国军官只是知道有“Emoji”的存在,并不知道如何将帝国官方语言转化为维达勋爵创立的这门新语,因此屡屡被勋爵使用原力吊死。我想,如果可以将日常语言转化为Emoji的话,有朝一日黑勋爵本尊来晒布巡视,我便可以对答如流了。

af0e52daf03d53bebb8590a858732f26.png

    不瞒你说,上面全是胡扯。不过Emoji在各位抽象青年的日常交流中起到的作用,实是有目共睹。本文将系统地介绍Emoji框架,并在Android系统上实现中文转Emoji翻译器。

6206786f5976126c73e449caf4708971.png

2015年牛牛津词典年度词语。《卫报》评论它表露出“嘲弄、揶揄的神态,天生便是残忍的模样”[1]

c515b50f79e877c79fb74e5df7d78d4e.gif

Emoji系统组成

    与一般的表情包以图片形式存储不同,Emoji系列表情在2010年被收录进了Unicode字符集中。而在今天,绝大多数智能设备都完整地支持该字符集,这就意味着Emoji字符在技术层面上早已是与汉字、英文字母等一般字符并列的存在。显示、存储与传输Emoji表情的技术原理与对应地操作中文、英文的原理相同。

    Emoji在编码上的通用性加速了它的传播,使其成为了全球使用最广泛的表情包。大面积地使用带来了为数不少的【正确性】问题。在上古时代,Emoji中所有出现人脸的表情都是类似辛普森一家中的黄脸,这种安排一度引起了有关肤色的争议。不仅如此,更早版本的部分表情中只有一种性别的人物版本,这又引起了有关性别偏见的争议。

    要解决这个问题,简单而暴力地使每一种表情都有各种肤色、各种性别的版本其实是不可行的,它会倍增原有的表情数量,甚至可能使Emoji字符集超出Unicode为其划定的范围。对此,官方给出的解决方案是加入两个特殊字符:“零宽连字”(ZWJ,在Unicode中的编号为U+200D)与“菲茨帕特里克修饰符”(U+1F3FB ~ U+1F3FF)。

零宽连字:这一特殊的Emoji字符本身并不会以任何方式显示,而会将自己和相邻的两个Emoji字符连接起来,使这三个字符以一个表情的形式合并显示。

    比如,这是一个男人:👨,把他和粮食用ZWJ连接起来:

👨+ZWJ+🌾 = 👨‍🌾

    同样地,这是一个女人:👩,把她和粮食用ZWJ连接起来:

👩+ZWJ+🌾 = 👩‍🌾

菲茨帕特里克修饰符:对应菲茨帕特里克度量对人类肤色的分类

2fc4b94ed1c161bd781d58cfc7086321.png

维基百科https://zh.wikipedia.org/wiki/%E7%B9%AA%E6%96%87%E5%AD%97

     例如,“黑发的黑人与金发的白人手拉着手”这一表情的合成过程为:

🧑+🏿+ZWJ+🤝+ZWJ+🧑+🏻 = 🧑🏿‍🤝‍🧑🏻

    即:人+白皮肤+连接+握手+连接+人+黑皮肤 = 黑发的黑人与金发的白人手拉着手。遗憾的是,我们发现许多设备虽然可以正确处理这一表情,却因为本地字符库中没有对应的表情字符而将其显示为三个表情。正确的显示应为:

6a6bbdc31774d159882ada5abfb91d27.png

    在ZWJ、菲茨帕特里克修饰符与控制性别、发型等特征的修饰性Emoji的共同作用下,仅“二人握手”这一类表情就可以有3,200种。

    事实上,大多数情况下,我们不需要考虑ZWJ与菲茨,因为它们已经隐式地被系统与原表情整合在一起显示、存储或传输。手机上的Emoji栏就是一个很好的例子:它并没有提供ZWJ、修饰符的手工输入功能,而是将常用的组合列在Emoji表中以供选用。

c515b50f79e877c79fb74e5df7d78d4e.gif

琢磨算法

    为了将中文翻译成Emoji,经过分析可得下列操作:

  1. 将用户输入的文段分割成词

  2. 以词为索引,在中文——Emoji表中查找对应的Emoji

    这便是简单的原始想法这个想法带来了几个技术问题:

  • 很显然,不能暴力地把中文文段按字符分隔。例如“桌子”一词的含义≠“桌”+“儿子”

  • 中文词条数不胜数,而且无序。如果将大量的词条添加到中文——Emoji表中,搜索将带来灾难性的高成本。

不过,众所周知,技术问题不是问题

  • 编写一个散列算法,为长度不等的中文词条创建长度相等的哈希代码,按照词条对应的哈希代码将词条添加到数据库的不同层中。这样,完全无序的中文此条变得部分有序

  • 编写一个匹配算法,从一个长句中节选出几个数据库中存在的关键词。对于数据库中不存在的词语,则不作合并以单字出现。

  • 只列举有限的常用词汇。对于不在数据库中的词汇,即匹配算法无法匹配的单字,则以谐音翻译

    然而,问题继续出现

  • 如何获取单字的拼音?

  • 在充满中文词条的数据库中搜索相当有限的几个拼音,是否算得上浪费?

    于是,继续解决问题

  • 为常用汉字建立拼音数据库

  • 词条数据库一分为二。主数据库存储词条——Emoji表,副数据库存储拼音单音——Emoji表

    然而,问题继续出现

  • 常用汉字同样浩若烟海,同样无序,搜索常用汉字又是一个灾难

    看到问题只剩一个,我心里(一阵爽快啦)

  • 以散列算法,为常用汉字拼音数据库分层,使其部分有序。

    仔细想了一想,在这个阶段没什么太大的问题了。

    真的吗?

    嗯,对,至少现在想不到什么太大的问题?

    真的吗?

    嗯……对,我想是的。

    Yeeeeeeeeeeeeaaaaaaaaaoooooooooop!

猪叫

c515b50f79e877c79fb74e5df7d78d4e.gif

散列算法

    散列算法,又称哈希算法,是一种把长度不等的数据转化为等长编码的算法。

设有散列函数f(x):

hash = f(data)

    散列算法一个重要的特征是,将data转化为hash的成本很低,但从hash得到data则需要很高成本,或根本不可能。因此,这种算法在密码学中应用很广泛。常用的散列算法有MD5、SHA-2等。

    在本例中,我们设计散列算法的目的在于:将一个完全无序的数据库部分有序化。设想,某中学有二十万个学生(再设想这是哪一所中学),学生王某元涉嫌毁坏公物被摄像头拍照。教导主任要拿着这张照片找到他,需要逐一比较二十万个学生,给了王某充分的窜逃时间。但如果主任一看到照片,就能准确地判断出王某是哪个年级、哪个班、哪个组的学生,就只需要与十几个学生进行比较,王某可谓插翅难逃。

    同样地,如果我们将(汉字,拼音)对以及(词条,Emoji)对简单地堆放在数据库中,搜索时只能依次比较,这种查找被称为线性查找,有一个看似很令人愉悦的O(n)的复杂度,但是n相当大时,时间成本仍然不小。而如果我们取(汉字,拼音)对中的汉字的哈希编码,依照这一编码将(汉字,拼音)对储存在数据库中对应的区块,就只需要在这一区块中进行查找。

    假设有3000个数据,哈希编码的长度为8位(二进制8位,10进制无符号取值范围为0~255),则一个数据块中平均仅有3000/256=11.72个数据。因此,散列算法给出的hash编码在取值范围内分布得越均匀,线性查找的成本就越小,查找就越快。

    为了帮助理解,下面我们将尝试对3,500个(汉字,拼音)对进行散列。

方案一:将存储汉字字符的每个字节数值相加,取相加结果的小端第三个字节为Hash。将每个(汉字,拼音)对保存在数据文件中其Hash值对应的行内。

方案二:将存储汉字字符的每个字节数值相加,取其平方,取平方结果的小端第三个字节为Hash。将每个(汉字,拼音)对保存在数据文件中其Hash值对应的行内。

方案三:取存储汉字字符的最后一个字节为Hash。

结果:

ba687b8316ab7a98f9bfb6faf30ed122.png 5ebadaaaa9c371ffd1cf015926a8210b.png 15d5c098c8a3a65339208efc91b62a9f.png

    很显然,方案二在三个方案中最优。按照这一思路进一步优化散列算法。

c515b50f79e877c79fb74e5df7d78d4e.gif

匹配算法

    分割词元,高深。搞这些,一般用深度学习,神经算法,哈哈。

    我们偏不搞(不会),下面是一种简单的匹配方案。

    试想:用户输入了一个名为source的字符串:

1ec917e33e91d0e33ef9efb452dd2a5e.png

    而我们的数据库中所有中文词条构成的数组为:

e937798779dcef7d0e21064122663ae8.png

    开始匹配时,以源字符串中的第1个字符“奥”作为参照,寻找第1个字符为“奥”的数据。第一个搜索到的是数据库中的第1条“奥利奥”,因此,以源字符串中的第2个字符“利”作为参照,发现数据库中第1条的第2个字符继续匹配。又以源字符串中第3个字符“给”作为参照,数据库第1条第3个字符“奥”不匹配。至此,得出数据库中第1条数据匹配度为2。

   上文以蓝色标出的循环继续进行,开始匹配数据库中第2条数据,得出匹配度为3。故可知第2条数据的匹配程度更高。所以源字符串中匹配的第一个词为“奥利给”。

     上文以绿色标出的循环继续进行,由于“奥利给”已经匹配,开始以“中”为参照匹配。这次,数据库中的两条数据匹配程度都是0,可知“中”是不在词条库中的单字,所以源字符串中匹配的第二个词为“中”本身。同理,第三个词为“给”本身。

    形象地来看,先用source[i]与database[j][k]比较,发现相同后k+1,i+1,比较第二个字符,直至出现不同,记录下database[j]对应的匹配程度,j+1,i复位为开始比较的字符的索引,比较第二条数据。如果第二条数据的匹配程度高于第一条,则临时将第二条数据作为匹配结果。如此继续比较,直至数据库被遍历完毕,这时的临时比较结果匹配程度最高,自动成为“正式”匹配结果。i向右移n位,n为具体匹配的字符数+1。

    将以上逻辑普遍化,则得到代码:

internal static List<string> SplitString(string source){    List<string> result = new List<string>();    for (int sourceindex = 0; sourceindex < source.Length;)    {        string addmeaning = "" + source[sourceindex];        int max_match_count = 0;        int match_count = 0;        List<string> meaninglist = Database.MeaningList[GetWordHash(source[sourceindex] + "", Encoding.UTF8)];        for (int meaninglist_index = 0; meaninglist_index < meaninglist.Count; meaninglist_index++)        {            int meaning_index = 0;            match_count = 0;            string match = null;            while (sourceindex < source.Length                && meaning_index < meaninglist[meaninglist_index].Length                && meaninglist[meaninglist_index][meaning_index] == source[sourceindex + match_count])            {                match += meaninglist[meaninglist_index][meaning_index];                match_count++;                meaning_index++;                if (sourceindex + match_count == source.Length)                    break;            }            if (match_count > max_match_count)            {                addmeaning = match;                max_match_count = match_count;            }        }        sourceindex += max_match_count;        if (max_match_count == 0)            sourceindex++;        result.Add(addmeaning);    }    return result;}
c515b50f79e877c79fb74e5df7d78d4e.gif

操作数据库

    按照上面提到的规划,我们建立三个数据库:

主数据库:

这一数据库存储(汉语词条,Emoji)对。随着后续发展,汉语词条的数量可能变得十分庞大,因此这一数据库中的数据需经散列算法操作

c656b30bab80a6f70f1904a2e92da8a9.png

主数据库在内存中以string[y][x]形式存储。y为将汉语词条作为散列函数参数得到的哈希编码,x为按分隔符分割一行数据得到的信息元数组的索引,如图示的i、i+1、i+2

副数据库:

这一数据库存储(拼音,Emoji)对。汉语拼音组合的数量有限,因此副数据库的条目在200个左右,且有一定顺序(即拼音字母顺序)不需要进行散列处理。

fad880adf084a52497d6c2d0717998cf.png

拼音数据库:

这一数据库存储(汉字,拼音)对。目前收录入库的汉字有3,500个左右,对其进行散列操作, 得到下列结构。此数据库在内存中的结构为string[y][x],y为汉字对应的哈希编码,x为按分隔符分割一行数据得到的信息元数组的索引。

8375d2e0d77bf343c7cb38d07669160d.png c515b50f79e877c79fb74e5df7d78d4e.gif

整合算法之后

    本文以Xamarin框架搭配C#完成安卓系统上的翻译器开发。Xamarin框架较为复杂,进一步了解请参阅: 

https://docs.microsoft.com/zh-cn/xamarin/get-started/what-is-xamarin(微软中文文档)

     长话短说,在简单地为算法编写Android应用程序后,我们得到了下面的成果:

ad81f7bd0a6c3f0998abdbaf12c9a435.png

应用图标,取“鬼”之吉意

1897929b9880662cb36f9fc2b0efc581.png

好了,我知道界面很丑。

967a6bcb0019177a9a47b9f1ed710356.gif

    目前,Emoooooii更新到了v0.3beta6版本。我们将持续在Github上更新源代码以及软件成品:

https://github.com/Pieski/Emoooooji(Github页面)

    如果你在从你的网络位置访问Github的过程中遇到了一些困难(也就是说,你在里面),请私信我们获取程序。注意,本程序遵循GNU GPLv3协议,用户可以自由使用/传播程序/源代码,但应醒目地标志来源

在扩充数据库后,我们将会在一篇新推文中发布正式版本。当然,您随时可以获取公测版本,并暂时地使用不完整的数据库。

03

1️⃣⬆️🍺🔟我们🉐第3️⃣篇推文,请继续关🐷👻🙆🐑🐎🙆👑。🎱💊说了,关🐷我们🎱🍺行了。

03

[1]https://web.archive.org/web/20170624083905/https://www.theguardian.com/commentisfree/2016/nov/24/tears-of-joy-emoji-worst-gloat-about-human-suffering(英文)

be0b6e6640cb5a54cb5b28c371b6cc1f.png

鬼人扬呀,马人王

一顿不吃,饿得慌

三天不看,有点凉

七日一更,还真香

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值