我在虎嗅上看过一篇关于Emoji的趣闻, 特别有意思, 在这里跟大家分享一下。里面提到了Emoji是怎么诞生的。

1999年前后,日本一个名叫栗田穰崇的年轻人,和许多直男一样, 给女友发的短信经常会被误解。比如,“知道了”被解读成“生气了”、“不耐烦了”,随后引发冷战。 于是少年栗田想:“如果能在文字里插入一些表情符号来表达感情,大家应该会需要吧!”

原始的Emoji就这么诞生了。

Emoji极大地丰富了我们的生活和通讯交流。Emoji诞生自程序员,但反过来对程序员也造成过一些困扰。

尤其对于面向C端的产品开发者, 用户越来越习惯于输入Emoji, 因此处理字符时遇到Emoji也只会越来越频繁。

Emoji的编码

Emoji字符是Unicode字符集中一部分. 特定形象的Emoji表情符号对应到特定的Unicode字节。

常见的Emoji表情符号在Unicode字符集中的范围和具体的字节映射关系, 可通过Emoji Unicode Tables查看到。

有意思的是, 在Emoji Unicode Tables表中,还给出了同一个Emoji表情在不同系统中的字体(是字体没错, Emoji的样式可通过字体文件改变)。

关于Emoji的最权威资料, 可以在Unicode® Emoji Charts上查阅到。

截止我写这篇文章的时刻, Emoji Charts 的最新版本是v3.0, v4.0还只是处于Beta阶段。

题外话补充一点: Unicode是一种字符编码方法,它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。

我们所知道的UTF-8、UTF-16等编码, 是对Unicode的不同实现方式。

如果要深入了解更多关于ASCII、Unicode、UTF-8、gb2312、gbk等编码的相关知识,在这里强烈推荐几篇文章,讲得非常好。

一些特殊的Emoji

在众多Emoji中, 有一些特殊的Emoji 并没有显示的样式, 只是起到了控制的作用。这些控制型的Emoji 与基础Emoji 出现在一起, 可以展示更多的样式。

比如 "变量选择器-15"(VARIATION SELECTOR-15, 简写VS-15): , 作用是让基础Emoji 变成更接近文本样式(text-style);

而 "变量选择器-16"(VARIATION SELECTOR-16, 简写VS-16): , 作用则是让基础Emoji 变成更接近Emoji样式(emoji-style).

VS-15 和 VS-16 加在基础Emoji字符的后面, 可以起到控制作用(前提是必须系统支持, 否则会被忽略)。

用一段Python代码来演示该例子:

# -*- coding: utf-8 -*-

# more info to see https://en.wikipedia.org/wiki/Emoji

# 符号分别是上图(截图自wiki)中的符号, 最后再加上一个“狗”的Emoji

sample_list = [u'\u2139', u'\u231B', u'\u26A0', u'\u2712', u'\u2764', u'\U0001F004', u'\U0001F21A', u'\U0001f436', ]

# 输出原样式

for code in sample_list:

print code,

print

print '-' * 20

# 后面加上VS-15

for code in sample_list:

print (code + u'\uFE0E'),

print

print '-' * 20

# 后面加上VS-16

for code in sample_list:

print (code + u'\uFE0F'),

其输出如下图, 第一行是原样式,第二行是加上VS-15后的样式,第三行是加上VS-16后的样式:

另外, 还有一些控制型的Emoji, 可以对人体肤色进行改变,改变对象仅限于"表示人身体部位的Emoji".

它们分别是: 共五个, 分别简称为: FITZ-1-2, FITZ-3, FITZ-4, FITZ-5, FITZ-6.

还有一个特殊的控制符: (ZERO WIDTH JOINER, 简写ZWJ), 起到了连接Emoji的作用, 从而将多个Emoji变成一个Emoji来显示. 同样,前提是必须系统支持, 否则会被忽略.

使用Python代码演示 FITZ-* 和 ZWJ:

# -*- coding: utf-8 -*-

# more info to see https://en.wikipedia.org/wiki/Emoji

# man_list 分别是: 男孩 女孩 男人 女人

man_list = [u'\U0001F466', u'\U0001F467', u'\U0001F468', u'\U0001F469']

# skin_color_list 分别是: 空字符串,表示默认 白种人 -->(不断加深肤色) 黑种人

skin_color_list = ['', u'\U0001F3FB', u'\U0001F3FC', u'\U0001F3FD', u'\U0001F3FE', u'\U0001F3FF', ]

for man in man_list:

for color in skin_color_list:

print (man + color),

print

print '-' * 20

# Emoji的连接符 (英文名为: ZERO WIDTH JOINER, 简写ZWJ )

# 如果系统支持: 连接(男人 + ZWJ + 女人 + ZWJ + 女孩)

print u'\U0001F468' + u'\u200D' + u'\U0001F469' + u'\u200D' + u'\U0001F467'

# 如果系统不支持: 连接(狗 + ZWJ + 猫 + ZWJ + 老鼠)

print u'\U0001f436' + u'\u200D' + u'\U0001f431' + u'\u200D' + u'\U0001f42d'

其输出如下图:

以上内容参考自维基百科

对Emoji 的介绍到该小节结束, 下面内容是一些关于实际中可能遇到的技术问题的解决方法。

MySQL存储Emoji

使用MySQL存储Emoji, 只需要数据表的字符集为utf8mb4即可, 即CHARSET=utf8mb4.

如果想要知道你的MySQL数据库是否支持utf8mb4编码, 可通过show charset; 输出当前安装的MySQL所支持的所有字符集, 查看输出中是否包含有utf8mb4.

另外, 有一些比较老的业务, 可能一开始设计时没考虑到需要支持Emoji, 那就需要修改数据库或数据表的字符集.

查看MySQL说支持的所有字符集

mysql> show charset;

查看某张表当前的字符集

mysql> show create table ;

创建默认字符集为utf8mb4的数据库.在该数据库中,如果创建表时是不指明字符集,则默认utf8mb4.

mysql> create database default charset utf8mb4;

创建字符集为utf8mb4的表, 数据库的默认字符集非utf8mb4也没问题.

mysql> create table `` (Column定义, Column定义, ...) DEFAULT CHARSET=utf8mb4;

修改已存在的数据库的字符集

mysql> alter database default charset = utf8mb4;

修改已存在的表的字符集

mysql> alter table default charset = utf8mb4;

使用正则表达式匹配Emoji

很可惜, Emoji的范围并没有明确的定义。正如上面提到了,Emoji Charts目前最新版本是v3.0, 未来Emoji的范围还会不断扩大。而且Emoji 在Unicode的分配中并不是连续的区间。

所以, 在这里我只能给出一个可行的匹配区间, 尽可能涵盖了基本常见的Emoj。

该匹配区间中会包含一些未定义的字符, 可能在某些系统会有定义,但是在另外的系统中并没有定义。毕竟Emoji是商业的产物。

- # symbols & pictographs

- # emoticons

- # transport & map symbols

- # other

下面使用Python代码来演示如何使用正则表达式替换(或找出)字符串中的Emoji:

# -*- coding: utf-8 -*-

import re

try:

# Wide UCS-4 build

myre = re.compile(u'['

u'\U0001F300-\U0001F64F'

u'\U0001F680-\U0001F6FF'

u'\u2600-\u2B55]+',

re.UNICODE)

except re.error:

# Narrow UCS-2 build

myre = re.compile(u'('

u'\ud83c[\udf00-\udfff]|'

u'\ud83d[\udc00-\ude4f\ude80-\udeff]|'

u'[\u2600-\u2B55])+',

re.UNICODE)

sss = u'I have a dog \U0001f436 . You have a cat \U0001f431 ! I smile \U0001f601 to you!'

print myre.sub('[Emoji]', sss) # 替换字符串中的Emoji

print myre.findall(sss) # 找出字符串中的Emoji

输出如下:

I have a dog [Emoji] . You have a cat [Emoji] ! I smile [Emoji] to you!

[u'\U0001f436', u'\U0001f431', u'\U0001f601']

上面例子中, 之所以使用try...except...来处理代码, 是考虑到 UCS-2 (Narrow UCS-2 build) 和 UCS-4 (Wide UCS-4 build) 的区别.

该Demo例子参考了stackoverflow上的精彩回答, 解答了我对此的困惑。

关于UCS-2和UCS-4的区别, 在上面提到的扩展阅读程序员趣味读物:谈谈Unicode编码中有提到, 值得一看.

本文中使用到的示例代码,可以在我的github下载到。

带有Emoji的字符串截取

在Python、JavaScript 这类编程语言中, 一个中文字符的长度为1,但是对大部分的Emoji(并非全部), 取长度则是2。下面使用Python做演示。

以中文的"汉"字取长度为例,取长度为1:

>>>len(u'汉')

1

而对于Emoji,以(该Emoji是一只萌萌的狗)为例,取长度为2:

>>>len(u'\U0001f436')

2

那么, 这就存在一个隐患, 在对字符串进行截断时可能从中间截断, 导致该字符显示为乱码, 甚至引发报错。

下面例子中, 对字符串进行截取时,正好从的中间截断了,出现了乱码:

>>>u'这是一只可爱的狗狗\U0001f436'.__len__()

11

>>>u'这是一只可爱的狗狗\U0001f436'[0:10]

这是一只可爱的狗狗???

实际场景中,对字符串进行截断是非常常见的需求,而且字符串往往可能是用户高度自由的输入内容, 那么包含Emoji的可能性其实是很高的。

一个具体的场景就是: 你正在开发了一款社交APP, 允许用户保存文字记录, 然后在应用的某个地方, 又需要显示这些文字记录的摘要,摘要只显示用户输入的前100个字符, 超出部分用省略号表示。

这种情况下,就不可避免的可能发生Emoji在中间被截断的问题。

解决方案也有多种:

全文进行正则匹配, 去掉大部分Emoji, 但是文本长度过长的情况消耗太大, 不值得.

先截取前200个字符, 匹配去掉Emoji再截取100个字符. 貌似可行. 但如果极端条件下前200个字符都是Emoji怎么办? 管他的.

运用上面提到的扩展阅读: 字符编码笔记:ASCII,Unicode和UTF-8中提到的UTF-8的编码规则, 对截断后字符串的最后字符进行检查, 发现是截断的字符即进行剔除。该方案可行, 不过你需要自己去实现了。

允许一定概率出现乱码, 乱码就乱码吧,概率不高,不影响主要体验。将更多精力放在避免其他bug上吧。

python表情符号编码_Emoji的编码以及常见问题处理相关推荐

  1. python表情符号编码大全_python玩转emoji ?

    原标题:python玩转emoji ? 1999年,emoji 正式诞生: 2007年,谷歌向维护不同平台和语言符号文字标椎化的统一码联盟发起提议,希望统一码联盟能出面标准化 emoji: 2009年 ...

  2. python表情符号编码大全_Emoji的编码以及常见问题处理

    我在虎嗅上看过一篇关于Emoji的趣闻, 特别有意思, 在这里跟大家分享一下.里面提到了Emoji是怎么诞生的. 1999年前后,日本一个名叫栗田穰崇的年轻人,和许多直男一样, 给女友发的短信经常会被 ...

  3. python表情符号编码大全_表情符号,当文本文件包含utf8和utf16时进行编码/解码...

    我有一个包含以下内容的文本文件:.... {"emojiCharts":{"emoji_icon":"\u2697","repos ...

  4. python表情,python玩转emoji表情

    1999年,emoji 正式诞生: 2007年,谷歌向维护不同平台和语言符号文字标椎化的统一码联盟发起提议,希望统一码联盟能出面标准化 emoji: 2009年,emoji 表情被纳入因特网 Unic ...

  5. Python 对图像进行base64编码及解码读取为numpy、opencv、matplot需要的格式

    Python 对图像进行base64编码及解码读取为numpy.opencv.matplot需要的格式 1. 效果图 2. 源码 参考 这篇博客将介绍Python如何对图像进行base64编解码及读取 ...

  6. 【廖雪峰python入门笔记】Unicode编码_UnicodeDecodeError处理

    1.Unicode编码的由来 字符串还有一个编码问题. 计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以, ...

  7. python numpy数组和one-hot编码相互转换

    a=[0,0,1,0,1,0,1]result=[] for i, x in enumerate(a):if x==1:result.append(i)print(result) python num ...

  8. python代码大全o-python文件编码及执行

    兼容中文编码 由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码. 当Python解释器读取源代码时,为了让它按UTF-8编 ...

  9. python模块之email: 电子邮件编码解码 (一、解码邮件)

    https://yq.aliyun.com/articles/54621 python模块之email: 电子邮件编码解码 (一.解码邮件) python自带的email模块是个很有意思的东西,它可以 ...

最新文章

  1. uber_Uber是如何制成的
  2. 声明式事务和编程式事务
  3. tensorflow 小于_坐姿不对,屏幕就变模糊!教你用TensorFlow做一款“隐形背背佳”...
  4. stringbuffer常用方法_第八讲:常用类库API
  5. Linux基本操作——Linux磁盘基本概念
  6. python os.system
  7. Java如何实现原子操作
  8. 操作系统课设 Nachos 实验六、七、八:Nachos 用户程序与系统调用、地址空间的扩展、系统调用 Exec() 与 Exit()
  9. servlet与jsp面试题
  10. Python函数的输出
  11. 半导体器件物理期末复习
  12. 百度地图级别与比例尺对照表
  13. 计算机无法访问文件怎么办,电脑通过局域网共享互传文件出现无法访问,怎么处理...
  14. 今日小程序推荐:文艺青年必备「轻芒杂志」
  15. 创业者的噩梦 -商业竞争究竟有多残酷和黑暗
  16. 自动化爬虫selenium基础教程
  17. 25句经典话(启迪人生)
  18. C-V2X在国内车路协同的应用
  19. Tableau 桑基图
  20. 输入某年某月某日,判断这一天是这一年的第几天python

热门文章

  1. STM32驱动_rc522
  2. 常见的电脑屏幕分辨率统计
  3. [Unity实战]仅用2步-虚拟相机Cinemachine简易使用
  4. 东芝TC358775XBG转换芯片:MIPI转LVDS(单/双路),替代ICN6202芯片
  5. 报表汇总工具FineReport中下拉框如何显示多列
  6. 推荐一份PHP程序员笔试题(附答案)
  7. [附源码]java毕业设计-在线排课系统
  8. 查看PHP版本的方法
  9. python的函数嵌套机制
  10. 【SSH】Hibernate学习(三)一对多、多对一、多对多