一封情书

这是一封让人面红耳赤、心惊肉跳、非常🐮逼的情书 (love-letter.png),未满十八岁者请由父母陪同阅 读。

话说我用Emacs+Smartisan T1发微博、聊微信/QQ、发朋友圈、回邮件、回短信 等等已经不是一天两天了,中间基本上非常爽,唯一觉得美中不足的是,我没有 办法发表情符号,每次只能很老土的发一个 :-) ,或者发一个 :-( ,土死 了,是吧。

作为一个逼格颇高(见我的 逼格咧 开源项目)的老黑客,我急切的需要向这个 世界宣布,我也可以很90后,我除了 :-):-( ,还会用 😁 和 😞 。相应 地,如果在手机上聊QQ、微信的话,我还会用 mood-smile.pngdisappointed-face.png

所以我就开始着手研究这个问题。首先,在Android上,几乎所有的Unicode表情 字符,Android都给它定制了一种彩色的字体,这个不知道它是怎么做到的。但 是用起来的感觉的确超级棒。

于是几乎所有Android的应用程序都自动支持了这些表情,我只要打出 😞 然后从 手机上发出去,手机上的显示自动就成了 disappointed-face.png 的样子。

问题出在微信上。它自起炉灶自己在Unicode的Private私有定制区里造了一堆的 表情符号,然后如果我打个 😞 再用微信发出去的话,手机上显示的是两个点点 .. 。这让我非常地头大,联系到本文的题目,这简直是逼我这个纯情的老黑 客同时追两个姑娘,一个美国的,点头Yes摇头No,另一个印度的,刚好反一反! 😭 。

我一直没有想到好的办法解决这个问题,郁闷啊郁闷。一度想要吞枪,不是自杀, 而是身为一个黑客,有时候不得不干点苦力活,英文叫bite the bullet,很洋 气是吧。我就想,我先在QQ里发一个笑脸,然后把字符拷贝回到PC上,然后在微 信里发一个一样的笑脸表情,然后把这个字符也拷贝回PC上,然后做一个表,把 每个QQ(Unicode)表情字符和微信的表情字符是怎么对应的给一一对照出来,以 后我在Emacs里统一打标准的Unicode表情字符,然后如果要在微信里发的话,就 查一下这个表,挨个翻译一下。

很庆幸我没有这样做,因为我真的是好懒啊。懒惰,是黑客的美德。

因为我偶然发现有一个很简单的方法,可以帮我找出这个字符表的对应关系。

那就是,Web版的微信:-)

在Web版的微信里,你可以用标准的Unicode表情字符!到了手机上,它会自动翻 译成微信版的表情! 👏 (这是一个鼓掌的Unicode,但是很可惜,我的系统上显 示不出来)

所以我写了一段脚本,

perl -e '$x = "😃"; use Encode; $x=decode_utf8($x); for (0..1800) { print ":", encode_utf8 chr(ord($x) + -1541 + $_)}'

它的输出结果是这样的:

:𞿾:𞿿:🀀:🀁:🀂:🀃:🀄:🀅:🀆:🀇:🀈:🀉:🀊:🀋:🀌:🀍:🀎:🀏:🀐:🀑:🀒:🀓:🀔:🀕:🀖:🀗:🀘:🀙:🀚:🀛:🀜:🀝:🀞:🀟:🀠:🀡:🀢:🀣:🀤:🀥:🀦:🀧:🀨:🀩:🀪:🀫:🀬:🀭:🀮:🀯:🀰:🀱:🀲:🀳:🀴:🀵:🀶:🀷:🀸:🀹:🀺:🀻:🀼:🀽:🀾:🀿:🁀:🁁:🁂:🁃:🁄:🁅:🁆:🁇:🁈:🁉:🁊:🁋:🁌:🁍:🁎:🁏:🁐:🁑:🁒:🁓:🁔:🁕:🁖:🁗:🁘:🁙:🁚:🁛:🁜:🁝:🁞:🁟:🁠:🁡:🁢:🁣:🁤:🁥:🁦:🁧:🁨:🁩:🁪:🁫:🁬:🁭:🁮:🁯:🁰:🁱:🁲:🁳:🁴:🁵:🁶:🁷:🁸:🁹:🁺:🁻:🁼:🁽:🁾:🁿:🂀:🂁:🂂:🂃:🂄:🂅:🂆:🂇:🂈:🂉:🂊:🂋:🂌:🂍:🂎:🂏:🂐:🂑:🂒:🂓:🂔:🂕:🂖:🂗:🂘:🂙:🂚:🂛:🂜:🂝:🂞:🂟:🂠:🂡:🂢:🂣:🂤:🂥:🂦:🂧:🂨:🂩:🂪:🂫:🂬:🂭:🂮:🂯:🂰:🂱:🂲:🂳:🂴:🂵:🂶:🂷:🂸:🂹:🂺:🂻:🂼:🂽:🂾:🂿:🃀:🃁:🃂:🃃:🃄:🃅:🃆:🃇:🃈:🃉:🃊:🃋:🃌:🃍:🃎:🃏:🃐:🃑:🃒:🃓:🃔:🃕:🃖:🃗:🃘:🃙:🃚:🃛:🃜:🃝:🃞:🃟:🃠:🃡:🃢:🃣:🃤:🃥:🃦:🃧:🃨:🃩:🃪:🃫:🃬:🃭:🃮:🃯:🃰:🃱:🃲:🃳:🃴:🃵:🃶:🃷:🃸:🃹:🃺:🃻:🃼:🃽:🃾:🃿:🄀:🄁:🄂:🄃:🄄:🄅:🄆:🄇:🄈:🄉:🄊:🄋:🄌:🄍:🄎:🄏:🄐:🄑:🄒:🄓:🄔:🄕:🄖:🄗:🄘:🄙:🄚:🄛:🄜:🄝:🄞:🄟:🄠:🄡:🄢:🄣:🄤:🄥:🄦:🄧:🄨:🄩:🄪:🄫:🄬:🄭:🄮:🄯:🄰:🄱:🄲:🄳:🄴:🄵:🄶:🄷:🄸:🄹:🄺:🄻:🄼:🄽:🄾:🄿:🅀:🅁:🅂:🅃:🅄:🅅:🅆:🅇:🅈:🅉:🅊:🅋:🅌:🅍:🅎:🅏:🅐:🅑:🅒:🅓:🅔:🅕:🅖:🅗:🅘:🅙:🅚:🅛:🅜:🅝:🅞:🅟:🅠:🅡:🅢:🅣:🅤:🅥:🅦:🅧:🅨:🅩:🅪:🅫:🅬:🅭:🅮:🅯:🅰:🅱:🅲:🅳:🅴:🅵:🅶:🅷:🅸:🅹:🅺:🅻:🅼:🅽:🅾:🅿:🆀:🆁:🆂:🆃:🆄:🆅:🆆:🆇:🆈:🆉:🆊:🆋:🆌:🆍:🆎:🆏:🆐:🆑:🆒:🆓:🆔:🆕:🆖:🆗:🆘:🆙:🆚:🆛:🆜:🆝:🆞:🆟:🆠:🆡:🆢:🆣:🆤:🆥:🆦:🆧:🆨:🆩:🆪:🆫:🆬:🆭:🆮:🆯:🆰:🆱:🆲:🆳:🆴:🆵:🆶:🆷:🆸:🆹:🆺:🆻:🆼:🆽:🆾:🆿:🇀:🇁:🇂:🇃:🇄:🇅:🇆:🇇:🇈:🇉:🇊:🇋:🇌:🇍:🇎:🇏:🇐:🇑:🇒:🇓:🇔:🇕:🇖:🇗:🇘:🇙:🇚:🇛:🇜:🇝:🇞:🇟:🇠:🇡:🇢:🇣:🇤:🇥:🇦:🇧:🇨:🇩:🇪:🇫:🇬:🇭:🇮:🇯:🇰:🇱:🇲:🇳:🇴:🇵:🇶:🇷:🇸:🇹:🇺:🇻:🇼:🇽:🇾:🇿:🈀:🈁:🈂:🈃:🈄:🈅:🈆:🈇:🈈:🈉:🈊:🈋:🈌:🈍:🈎:🈏:🈐:🈑:🈒:🈓:🈔:🈕:🈖:🈗:🈘:🈙:🈚:🈛:🈜:🈝:🈞:🈟:🈠:🈡:🈢:🈣:🈤:🈥:🈦:🈧:🈨:🈩:🈪:🈫:🈬:🈭:🈮:🈯:🈰:🈱:🈲:🈳:🈴:🈵:🈶:🈷:🈸:🈹:🈺:🈻:🈼:🈽:🈾:🈿:🉀:🉁:🉂:🉃:🉄:🉅:🉆:🉇:🉈:🉉:🉊:🉋:🉌:🉍:🉎:🉏:🉐:🉑:🉒:🉓:🉔:🉕:🉖:🉗:🉘:🉙:🉚:🉛:🉜:🉝:🉞:🉟:🉠:🉡:🉢:🉣:🉤:🉥:🉦:🉧:🉨:🉩:🉪:🉫:🉬:🉭:🉮:🉯:🉰:🉱:🉲:🉳:🉴:🉵:🉶:🉷:🉸:🉹:🉺:🉻:🉼:🉽:🉾:🉿:🊀:🊁:🊂:🊃:🊄:🊅:🊆:🊇:🊈:🊉:🊊:🊋:🊌:🊍:🊎:🊏:🊐:🊑:🊒:🊓:🊔:🊕:🊖:🊗:🊘:🊙:🊚:🊛:🊜:🊝:🊞:🊟:🊠:🊡:🊢:🊣:🊤:🊥:🊦:🊧:🊨:🊩:🊪:🊫:🊬:🊭:🊮:🊯:🊰:🊱:🊲:🊳:🊴:🊵:🊶:🊷:🊸:🊹:🊺:🊻:🊼:🊽:🊾:🊿:🋀:🋁:🋂:🋃:🋄:🋅:🋆:🋇:🋈:🋉:🋊:🋋:🋌:🋍:🋎:🋏:🋐:🋑:🋒:🋓:🋔:🋕:🋖:🋗:🋘:🋙:🋚:🋛:🋜:🋝:🋞:🋟:🋠:🋡:🋢:🋣:🋤:🋥:🋦:🋧:🋨:🋩:🋪:🋫:🋬:🋭:🋮:🋯:🋰:🋱:🋲:🋳:🋴:🋵:🋶:🋷:🋸:🋹:🋺:🋻:🋼:🋽:🋾:🋿:🌀:🌁:🌂:🌃:🌄:🌅:🌆:🌇:🌈:🌉:🌊:🌋:🌌:🌍:🌎:🌏:🌐:🌑:🌒:🌓:🌔:🌕:🌖:🌗:🌘:🌙:🌚:🌛:🌜:🌝:🌞:🌟:🌠:🌡:🌢:🌣:🌤:🌥:🌦:🌧:🌨:🌩:🌪:🌫:🌬:🌭:🌮:🌯:🌰:🌱:🌲:🌳:🌴:🌵:🌶:🌷:🌸:🌹:🌺:🌻:🌼:🌽:🌾:🌿:🍀:🍁:🍂:🍃:🍄:🍅:🍆:🍇:🍈:🍉:🍊:🍋:🍌:🍍:🍎:🍏:🍐:🍑:🍒:🍓:🍔:🍕:🍖:🍗:🍘:🍙:🍚:🍛:🍜:🍝:🍞:🍟:🍠:🍡:🍢:🍣:🍤:🍥:🍦:🍧:🍨:🍩:🍪:🍫:🍬:🍭:🍮:🍯:🍰:🍱:🍲:🍳:🍴:🍵:🍶:🍷:🍸:🍹:🍺:🍻:🍼:🍽:🍾:🍿:🎀:🎁:🎂:🎃:🎄:🎅:🎆:🎇:🎈:🎉:🎊:🎋:🎌:🎍:🎎:🎏:🎐:🎑:🎒:🎓:🎔:🎕:🎖:🎗:🎘:🎙:🎚:🎛:🎜:🎝:🎞:🎟:🎠:🎡:🎢:🎣:🎤:🎥:🎦:🎧:🎨:🎩:🎪:🎫:🎬:🎭:🎮:🎯:🎰:🎱:🎲:🎳:🎴:🎵:🎶:🎷:🎸:🎹:🎺:🎻:🎼:🎽:🎾:🎿:🏀:🏁:🏂:🏃:🏄:🏅:🏆:🏇:🏈:🏉:🏊:🏋:🏌:🏍:🏎:🏏:🏐:🏑:🏒:🏓:🏔:🏕:🏖:🏗:🏘:🏙:🏚:🏛:🏜:🏝:🏞:🏟:🏠:🏡:🏢:🏣:🏤:🏥:🏦:🏧:🏨:🏩:🏪:🏫:🏬:🏭:🏮:🏯:🏰:🏱:🏲:🏳:🏴:🏵:🏶:🏷:🏸:🏹:🏺:🏻:🏼:🏽:🏾:🏿:🐀:🐁:🐂:🐃:🐄:🐅:🐆:🐇:🐈:🐉:🐊:🐋:🐌:🐍:🐎:🐏:🐐:🐑:🐒:🐓:🐔:🐕:🐖:🐗:🐘:🐙:🐚:🐛:🐜:🐝:🐞:🐟:🐠:🐡:🐢:🐣:🐤:🐥:🐦:🐧:🐨:🐩:🐪:🐫:🐬:🐭:🐮:🐯:🐰:🐱:🐲:🐳:🐴:🐵:🐶:🐷:🐸:🐹:🐺:🐻:🐼:🐽:🐾:🐿:👀:👁:👂:👃:👄:👅:👆:👇:👈:👉:👊:👋:👌:👍:👎:👏:👐:👑:👒:👓:👔:👕:👖:👗:👘:👙:👚:👛:👜:👝:👞:👟:👠:👡:👢:👣:👤:👥:👦:👧:👨:👩:👪:👫:👬:👭:👮:👯:👰:👱:👲:👳:👴:👵:👶:👷:👸:👹:👺:👻:👼:👽:👾:👿:💀:💁:💂:💃:💄:💅:💆:💇:💈:💉:💊:💋:💌:💍:💎:💏:💐:💑:💒:💓:💔:💕:💖:💗:💘:💙:💚:💛:💜:💝:💞:💟:💠:💡:💢:💣:💤:💥:💦:💧:💨:💩:💪:💫:💬:💭:💮:💯:💰:💱:💲:💳:💴:💵:💶:💷:💸:💹:💺:💻:💼:💽:💾:💿:📀:📁:📂:📃:📄:📅:📆:📇:📈:📉:📊:📋:📌:📍:📎:📏:📐:📑:📒:📓:📔:📕:📖:📗:📘:📙:📚:📛:📜:📝:📞:📟:📠:📡:📢:📣:📤:📥:📦:📧:📨:📩:📪:📫:📬:📭:📮:📯:📰:📱:📲:📳:📴:📵:📶:📷:📸:📹:📺:📻:📼:📽:📾:📿:🔀:🔁:🔂:🔃:🔄:🔅:🔆:🔇:🔈:🔉:🔊:🔋:🔌:🔍:🔎:🔏:🔐:🔑:🔒:🔓:🔔:🔕:🔖:🔗:🔘:🔙:🔚:🔛:🔜:🔝:🔞:🔟:🔠:🔡:🔢:🔣:🔤:🔥:🔦:🔧:🔨:🔩:🔪:🔫:🔬:🔭:🔮:🔯:🔰:🔱:🔲:🔳:🔴:🔵:🔶:🔷:🔸:🔹:🔺:🔻:🔼:🔽:🔾:🔿:🕀:🕁:🕂:🕃:🕄:🕅:🕆:🕇:🕈:🕉:🕊:🕋:🕌:🕍:🕎:🕏:🕐:🕑:🕒:🕓:🕔:🕕:🕖:🕗:🕘:🕙:🕚:🕛:🕜:🕝:🕞:🕟:🕠:🕡:🕢:🕣:🕤:🕥:🕦:🕧:🕨:🕩:🕪:🕫:🕬:🕭:🕮:🕯:🕰:🕱:🕲:🕳:🕴:🕵:🕶:🕷:🕸:🕹:🕺:🕻:🕼:🕽:🕾:🕿:🖀:🖁:🖂:🖃:🖄:🖅:🖆:🖇:🖈:🖉:🖊:🖋:🖌:🖍:🖎:🖏:🖐:🖑:🖒:🖓:🖔:🖕:🖖:🖗:🖘:🖙:🖚:🖛:🖜:🖝:🖞:🖟:🖠:🖡:🖢:🖣:🖤:🖥:🖦:🖧:🖨:🖩:🖪:🖫:🖬:🖭:🖮:🖯:🖰:🖱:🖲:🖳:🖴:🖵:🖶:🖷:🖸:🖹:🖺:🖻:🖼:🖽:🖾:🖿:🗀:🗁:🗂:🗃:🗄:🗅:🗆:🗇:🗈:🗉:🗊:🗋:🗌:🗍:🗎:🗏:🗐:🗑:🗒:🗓:🗔:🗕:🗖:🗗:🗘:🗙:🗚:🗛:🗜:🗝:🗞:🗟:🗠:🗡:🗢:🗣:🗤:🗥:🗦:🗧:🗨:🗩:🗪:🗫:🗬:🗭:🗮:🗯:🗰:🗱:🗲:🗳:🗴:🗵:🗶:🗷:🗸:🗹:🗺:🗻:🗼:🗽:🗾:🗿:😀:😁:😂:😃:😄:😅:😆:😇:😈:😉:😊:😋:😌:😍:😎:😏:😐:😑:😒:😓:😔:😕:😖:😗:😘:😙:😚:😛:😜:😝:😞:😟:😠:😡:😢:😣:😤:😥:😦:😧:😨:😩:😪:😫:😬:😭:😮:😯:😰:😱:😲:😳:😴:😵:😶:😷:😸:😹:😺:😻:😼:😽:😾:😿:🙀:🙁:🙂:🙃:🙄:🙅:🙆:🙇:🙈:🙉:🙊:🙋:🙌:🙍:🙎:🙏:🙐:🙑:🙒:🙓:🙔:🙕:🙖:🙗:🙘:🙙:🙚:🙛:🙜:🙝:🙞:🙟:🙠:🙡:🙢:🙣:🙤:🙥:🙦:🙧:🙨:🙩:🙪:🙫:🙬:🙭:🙮:🙯:🙰:🙱:🙲:🙳:🙴:🙵:🙶:🙷:🙸:🙹:🙺:🙻:🙼:🙽:🙾:🙿:🚀:🚁:🚂:🚃:🚄:🚅:🚆:🚇:🚈:🚉:🚊:🚋:🚌:🚍:🚎:🚏:🚐:🚑:🚒:🚓:🚔:🚕:🚖:🚗:🚘:🚙:🚚:🚛:🚜:🚝:🚞:🚟:🚠:🚡:🚢:🚣:🚤:🚥:🚦:🚧:🚨:🚩:🚪:🚫:🚬:🚭:🚮:🚯:🚰:🚱:🚲:🚳:🚴:🚵:🚶:🚷:🚸:🚹:🚺:🚻:🚼:🚽:🚾:🚿:🛀:🛁:🛂:🛃:🛄:🛅:🛆:🛇:🛈:🛉:🛊:🛋:🛌:🛍:🛎:🛏:🛐:🛑:🛒:🛓:🛔:🛕:🛖:🛗:🛘:🛙:🛚:🛛:🛜:🛝:🛞:🛟:🛠:🛡:🛢:🛣:🛤:🛥:🛦:🛧:🛨:🛩:🛪:🛫:🛬:🛭:🛮:🛯:🛰:🛱:🛲:🛳:🛴:🛵:🛶:🛷:🛸:🛹:🛺:🛻:🛼:🛽:🛾:🛿:🜀:🜁:🜂:🜃:🜄:🜅:🜆

你可以看一下你的系统里能显示多少个字符:-) 有很多还不是微信的表情符呢。

在Web版的微信里,发出去的是这样的:

web-qq.png

在手机上,我看到的是这样的:

weixin-full-emoji.png

这里可以长按弹出菜单拷贝下来,传回到PC上就得到了微信版表情字符的码表。

你可以看到我在每个表情字符中间都夹了一个冒号。接下来说一说这个原因。

我曾经想得挺美,生成这个对应表也可以用一行长长的perl代码搞定。结果发现 不行,Unicode发出去的字符和微信版本返回来的字符不是一一对应关系!也就 是说Unicode发出去 ABCD ,微信返回来 UVWXY ,多了一个出来,我没法很 容易地确定中间是ABCD里的哪个,对应了 UVWXY 里的哪两个。

做为一个老黑客,我真的是很有点小聪明的呢,我想到的办法是在 ABCD 中间夹 一个冒号,A:B:C:D,这样微信返回来的也有一个冒号,U:VW:X:Y,一眼就能看 出来是谁多了一个字符出来,就是那个B呀!

最后我又非常注意软件重用,没有全部用perl去生成这个表,而是先用了一下diff,这样的话对应关系更明显了:

Unicode的表是这样的:

58, :
127214, 🃮
58, :
127215, 🃯
58, :
127216, 🃰
58, :
127217, 🃱
58, :
127218, 🃲
58, :
127219, 🃳
58, :
127220, 🃴
58, :
127221, 🃵
58, :
127222, 🃶
58, :
127223, 🃷

微信的表是这样的:

58, :
127214, 🃮
58, :
127215, 🃯
58, :
127216, 🃰
58, :
127217, 🃱
58, :
127218, 🃲
58, :
127219, 🃳
58, :
127220, 🃴
58, :
127221, 🃵
58, :
127222, 🃶
58, :
127223, 🃷

可以看到并不是每个Unicode表情符微信都会造一个自己的版本,有些没有造的 它就直接给你显示个..,但拷贝出来之后的码跟原来的Unicode码还是一样的。 我做个diff,就把这些一样的码全部都过滤掉了,只剩下那些需要到最后的表里 来的表情:

14c14
< 57645, 
---
> 126980, 🀄
742c742
< 58674, 
---
> 127344, 🅰
744c744
< 58675, 
---
> 127345, 🅱
770c770
< 58677, 
---
> 127358, 🅾
772c772
< 57679, 
---
> 127359, 🅿

最后,写出了一个脚本,能直接把Unicode表情符转换成微信的表情符: unicode-to-wx.pl

最后,又写了一个脚本,能把 :-) 等古典的表情符转换成Unicode的表情符: emoji-to-unicode.pl

最后,又更新了我的SDIM输入法,能够用zuface.disappointed来打出一个苦逼的脸:😞。bhj_ime.py

最后,更新了我的Emacs + Smartisan T1发微信朋友圈和微博的脚本,我可以编 辑一段文本,然后同时自动发在微信朋友圈和微博上。等我发完这篇博客我会演 示一下,一会儿见哦!

最后,那个Unicode转成微信表情会多出来一个字符的表情就是,本文的题目, 一封情书。💌,你把这个字符发到微博上,看到的是 love-letter.png ,发到微信上,看到的是 love-letter-wx.png

最后的最后的最后,如果你看了我这封情书,愿意跟我在一起的话,我已经开好 了 🏩 ,又是一个无法显示的Unicode表情,Unicode Name is Love Hotel,日本 人搞出来的东东,在微信上会这样显示: love-hotel.png ,等你来啊。

Love Hotel纯属开个玩笑,请考虑投简历到锤子科技,来跟我们一起,干!