emoji字符长度的处理

简介

在项目开发中偶尔会遇到emoji表情存入数据库但是无法准确计算长度(个数和实际所占字符长度)
最开始遇到这个情况是在开发后台管理系统时,标题中需要插入emoji表情我用的是emoji-mart-vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import { Picker } from 'emoji-mart-vue'
```

比如👩‍👩‍👧‍👧字符就占用11字符长度
感觉应该通过正则来进行筛别
最后找到了一个标准的正则表达式项目 [EmojiCharString](https://github.com/thomasliew/EmojiCharString)
你可以安装或者在源代码中找到正则并使用它(我采用的这个)

## 过程

> 原理就是点击emoji的Picker时候自动获取某个输入框内文本,通过正则计算长度,
然后追加到第一位,重新拼接,重新赋值
如果是先点击了输入框则获取当前点击位置,截取前后两部分内容,然后在插入表情之后进行上一步操作.
具体看代码,哪里不明白可以给我留言.

## 贴出实际使用的代码

```js
//data
return{
titleCount: 0,//标题长度
blurIndexTitle: 0,//光标位置
emoji_in_title_l: 0,//标题中emoji个数
}
//methods
handleInputFocusTitle(e){
this.blurIndexTitle = e.srcElement.selectionStart;//失去焦点获取光标位置
console.log('光标位置',this.blurIndexTitle);
},
addEmojiToTitle(emoji){//标题
console.log(emoji);
let insertText = emoji.native;//获取到的emoji(Array) ["😘"]
let emoji_l = _.toArray(insertText)[0].length;//emoji所占字符长度 真实的2 4 11...
//_.toArray需要用到用到lodash库
//`import lodash from "lodash";`
let holdText = this.form.title;//获取待 被插入的文本
let beforeText = holdText.substring(0, this.blurIndexTitle);//从[光标位置]分割文本,前部分
let afterText = holdText.substring( this.blurIndexTitle, holdText.length);//从[光标位置]分割文本,后部分
this.form.title = beforeText + emoji.native + afterText;//插入emoji,拼接还原文本
//执行被插入emoji之后的操作
this.blurIndexTitle = this.blurIndexTitle + emoji_l;//常规apple的emoji占2~1x个字符,更新文本长度
console.log('本次插入的emoji真实长度',emoji_l);
this.emoji_in_title_l += 0;
console.log('标题中emoji的个数',this.emoji_in_title_l);
},
//computed
returnTitleLength(){
let count = 0;
let a = this.form.title?this.form.title.match(/[\u0000-\u00ff]/g)?this.form.title.match(/[\u0000-\u00ff]/g):[]:[]; //半角
let b = this.form.title?this.form.title.match(/[\u4e00-\u9fa5]/g)?this.form.title.match(/[\u4e00-\u9fa5]/g):[]:[]; //中文
let c = this.form.title?this.form.title.match(/[\uff00-\uffff]/g)?this.form.title.match(/[\uff00-\uffff]/g):[]:[]; //全角
let d = this.form.title?this.form.title.match(/[\u300a-\u300b]/g)?this.form.title.match(/[\u300a-\u300b]/g):[]:[]; //《 》
let e = this.form.title?this.form.title.match(/\ud83c[\udffb-\udfff](?=\ud83c[\udffb-\udfff])|(?:[^\ud800-\udfff][\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]?|[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?)*/g)?this.form.title.match(/\ud83c[\udffb-\udfff](?=\ud83c[\udffb-\udfff])|(?:[^\ud800-\udfff][\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]?|[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?)*/g):[]:[];
// console.log( a,b,c,d );
count = a.length*-1 + b.length*-.5 + c.length*-.5 + d.length*-.5 + e.length*1.5;//emoji字符符合汉字正则也符合开源项目代码中的正则,这里灵活运用,看需求
this.titleCount = count + this.emoji_in_title_l;//标题真实长度包含emoji 存起来验证表单用

// console.log('除表情外的验证长度:',count);
// console.log('标题验证长度',this.titleCount);
// console.log('标题真实长度',this.form.title.length);
// console.log( '-'.repeat(30) );
return this.titleCount;
},