天天看點

Emoji表情

轉載請聲明出處哦~,本篇文章釋出于 fushengwushi 的部落格:https://www.fushengwushi.com/archives/1131

Emoji表情 – 是開發中常遇到的一個難點,無論是存儲還是識别,都有一定的難度,下面來具體介紹一下:

一、含義

Emoji表情

emoji 是可以插入文字的圖形符号,是日語詞“絵文字”(“えもじ”)的音譯。

Emoji 在上個世紀90年代,由日本電信商引入服務,最早用于在短消息之中插入表情。2007年,蘋果公司的 iPhone 支援了 Emoji,導緻它在全世界範圍的流行。目前全球約有90%的線上使用者頻繁使用emoji,每天有60億個emoji表情符号被傳送。

二、标準化

2010年10月釋出的Unicode 6.0版首次收錄emoji編碼,從此,Emoji表情就是一個文字,不過會被渲染成圖形而已。

Emoji 的國際标準在 2015 年出台,截止目前(2020-07),已經是v13.0版本了。

三、渲染實作

Unicode 隻是規定了 Emoji 的碼點和含義,但具體的實作與展示則依賴于其展示的系統,如果系統無法識别該Emoji表情,則無法正常顯示。

同時,不同的系統,展示的方式同樣有差別,同一個Emoji表情,在不同的系統上的展示可能不同。

Emoji表情

四、表情存儲

Emoji表情的mysql存儲一直是開發中常遇到的情景,一般而言,正常的方案是采用utf8mb4編碼方式進行存儲。

如果業務上更改utf8mb4存儲成本過大的話,也可以通過json_encode轉為unicode編碼,或者用varbinary類型進行儲存。

五、表情的識别

emoji表情與其他字元的區分一直是個難點,如果想要知道一個字元串中有多少個Emoji表情,或者去除字元串中的Emoji表情等,都需要對Emoji表情進行識别。

一般而言,Emoji表情的識别有兩種方案。

方案一:位元組數

可以通過位元組數來進行,畢竟大部分Emoji表情的位元組數為4,可以跟其他字元區分開,如下

// 提取所含emoji表情字元數

func GetEmojiNum(text string) int {

num := 0

for _, value := range text {

_, size := utf8.DecodeRuneInString(string(value))

if size > 3 {

num++

}

}

return num

}

如果要求不是非常精确的話,這種方法完全可以滿足我們的需求,但肯定會有一部分Emoji表情會被遺漏,因為很多Emoji表情的位元組數并不是4。

方案二:編碼範圍比對

如果想要精确的比對出Emoji表情,就需要拿到所有Emoji表情的編碼範圍,然後通過正則進行比對。

regex := "[\U0001f004]|[\U0001f0cf]|[\U0001f170-\U0001f171]|[\U0001f17e-\U0001f17f]|[\U0001f17f]|[\U0001f18e]|[\U0001f191-\U0001f19a]|[\U0001f201-\U0001f202]|[\U0001f21a]|[\U0001f22f]|[\U0001f232-\U0001f23a]|[\U0001f250-\U0001f251]|[\U0001f300-\U0001f321]|[\U0001f324-\U0001f393]|[\U0001f396-\U0001f397]|[\U0001f399]|[\U0001f39a-\U0001f39b]|[\U0001f39e-\U0001f3f0]|[\U0001f3f3-\U0001f3f5]|[\U0001f3f7-\U0001f4fd]|[\U0001f4ff-\U0001f53d]|[\U0001f549-\U0001f54e]|[\U0001f550-\U0001f567]|[\U0001f56f-\U0001f570]|[\U0001f573-\U0001f57a]|[\U0001f587]|[\U0001f58a-\U0001f58d]|[\U0001f590]|[\U0001f595-\U0001f596]|[\U0001f5a4-\U0001f5a5]|[\U0001f5a8]|[\U0001f5b1-\U0001f5b2]|[\U0001f5bc]|[\U0001f5c2-\U0001f5c4]|[\U0001f5d1-\U0001f5d3]|[\U0001f5dc-\U0001f5de]|[\U0001f5e1]|[\U0001f5e3]|[\U0001f5e8]|[\U0001f5ef]|[\U0001f5f3]|[\U0001f5fa-\U0001f64f]|[\U0001f680-\U0001f6c5]|[\U0001f6cb-\U0001f6d2]|[\U0001f6d5-\U0001f6d7]|[\U0001f6e0-\U0001f6e5]|[\U0001f6e9]|[\U0001f6eb-\U0001f6ec]|[\U0001f6f0]|[\U0001f6f3-\U0001f6fc]|[\U0001f7e0-\U0001f93a]|[\U0001f93c-\U0001f945]|[\U0001f947-\U0001f978]|[\U0001f97a-\U0001f9cb]|[\U0001f9cd-\U0001fa74]|[\U0001fa78-\U0001fa86]|[\U0001fa90-\U0001faa8]|[\U0001fab0-\U0001fab6]|[\U0001fac0-\U0001fac2]|[\U0001fad0-\U0001fad6]|[\u00a9]|[\u00ae]||[\u203c]|[\u2049]|[\u2122]|[\u2139]|[\u2194-\u2199]|[\u21a9-\u21aa]|[\u231a-\u231b]|[\u2328]|[\u23cf]|[\u23e9]|[\u23ea-\u23f3]|[\u23f8-\u23fa]|[\u24c2]|[\u25aa-\u25ab]|[\u25b6]|[\u25c0]|[\u25fb-\u25fe]|[\u2600-\u2604]|[\u260e]|[\u2611]|[\u2614-\u2615]|[\u2618]|[\u261d]|[\u2620]|[\u2622-\u2623]|[\u2626]|[\u262a]|[\u262e-\u262f]|[\u2638-\u263a]|[\u2640]|[\u2642]|[\u2648-\u2653]|[\u265f-\u2660]|[\u2663]|[\u2665-\u2666]|[\u2668]|[\u267b]|[\u267e-\u267f]|[\u2692-\u2697]|[\u2699]|[\u269b-\u269c]|[\u26a0-\u26a1]|[\u26a7]|[\u26aa-\u26ab]|[\u26b0-\u26b1]|[\u26bd-\u26be]|[\u26c4-\u26c5]|[\u26c8]|[\u26ce-\u26cf]|[\u26d1]|[\u26d3-\u26d4]|[\u26e9-\u26ea]|[\u26f0-\u26f5]|[\u26f7-\u26fa]|[\u26fd]|[\u2702]|[\u2705]|[\u2708-\u270d]|[\u270f]|[\u2712]|[\u2714]|[\u2716]|[\u271d]|[\u2721]|[\u2728]|[\u2733-\u2734]|[\u2744]|[\u2747]|[\u274c]|[\u274e]|[\u2753-\u2755]|[\u2757]|[\u2763-\u2764]|[\u2795-\u2797]|[\u27a1]|[\u27b0]|[\u27bf]|[\u2934-\u2935]|[\u2b05-\u2b07]|[\u2b1b-\u2b1c]|[\u2b50]|[\u2b55]|[\u3030]|[\u303d]|[\u3297]|[\u3299]"

rCharacter := regexp.MustCompile(regex)

num := len(rCharacter.FindAllStringSubmatch(text,-1))

上面我們拿到了所有的Emoji表情,但實際的業務場景中,我們所認知的Emoji表情應該是所有的圖形符号,而有些圖形符号并不屬于Emoji表情的範圍,是以我們需要再加上這些圖形符号的編碼範圍。

雜項符号及圖形768個字元中有637是emoji;增補符号及圖形82個字元中有80個是emoji;所有80個表情符号都是emoji;交通及地圖符号103個字元中有92個是emoji;雜項符号256個字元中有80個是emoji;裝飾符号192個字元中有33個是emoji。

下面是結合後的正則比對:

// 提取所含emoji表情字元數

func GetEmojiNum(text string) int {

regex := "[\U0001f004]|[\U0001f0cf]|[\U0001f170-\U0001f171]|[\U0001f17e-\U0001f17f]|[\U0001f17f]|[\U0001f18e]|[\U0001f191-\U0001f19a]|[\U0001f1e6-\U0001f1ff]{1,2}|[\U0001f201-\U0001f202]|[\U0001f21a]|[\U0001f22f]|[\U0001f232-\U0001f23a]|[\U0001f250-\U0001f251]|[\U0001f300-\U0001f64f]|[\U0001f680-\U0001f6ff]|[\U0001f7e0-\U0001fa74]|[\U0001fa78-\U0001fa86]|[\U0001fa90-\U0001faa8]|[\U0001fab0-\U0001fab6]|[\U0001fac0-\U0001fac2]|[\U0001fad0-\U0001fad6]|[\u00a9]|[\u00ae]|[\u203c]|[\u2049]|[\u2122]|[\u2139]|[\u2194-\u2199]|[\u21a9-\u21aa]|[\u231a-\u231b]|[\u2328]|[\u23cf]|[\u23e9]|[\u23ea-\u23f3]|[\u23f8-\u23fa]|[\u24c2]|[\u25aa-\u25ab]|[\u25b6]|[\u25c0]|[\u25fb-\u25fe]|[\u2600-\u26ff]|[\u2700-\u27bf]|[\u2934-\u2935]|[\u2b05-\u2b07]|[\u2b1b-\u2b1c]|[\u2b50]|[\u2b55]|[\u3030]|[\u303d]|[\u3297]|[\u3299]"

rCharacter := regexp.MustCompile(regex)

return len(rCharacter.FindAllStringSubmatch(text,-1))

}

當然,這種做法還是存在一定誤差的,因為一些Emoji表情實際是由多個編碼組合而成的,是以會出現,一個Emoji表情,但是别出來的表情數>1,但相對而言,精确度比之位元組比較不在一個等級。

而且這種方法僅是在這種擷取Emoji表情數,或者替換/提取Emoji表情等需要明确每一個Emoji表情的情景會出現上述不準确情況,如果你的業務需求僅僅是判斷字元串中是否包含Emoji表情,上述方案則是完全沒問題的。

六、參考連結

Full Emoji List

WikiEmoji