关于emoji:一枚笑脸-emoji估值-20-亿美元这个开源项目有点强

从事 AI 技术开发的同学应该晓得,GitHub 上有一个 Logo 为笑脸 Emoji 的开源我的项目:Hugging Face。它的 transformer 模型在 GitHub 领有 6.2 万 star 量,从以后我的项目估值来看,一个 Star 价值 1600 美元。 五年前,一家来自纽约的守业公司 Hugging Face 发表,它为那些颇感无聊的青少年打造了一款 iPhone 聊天机器人利用,能够分享一些电脑生成的人脸和笑话,也能够和 Siri 玩互动。换句话说,他们想打造一个能够了解任何类型对话主题的聊天机器人。 「咱们能够和人工智能议论所有,就像你在科幻小说中看到的那样。」 这款利用完全符合三位创始人的商业理念 —— 对于「凋谢畛域的对话式人工智能」的设想,但根本没有让 Hugging Face 赚到什么钱。 转折产生在 2018 年,相应的对象不是青少年,而是开发者。那时候,Hugging Face 的创始人开始在线收费分享应用程序的底层代码,包含谷歌、微软在内的一些出名科技公司的钻研人员开始将其利用于本人的 AI 程序。 现在,聊天机器人早已从 App Store 中下架,Hugging Face 已成为即用型机器学习模型的核心,超过 10000 家组织以这里为终点,为其业务创立了 AI 驱动的工具。 前不久,这家备受瞩目的开源守业公司 Hugging Face 发表实现 1 亿美元 C 轮融资,本轮融资仍由 Lux Capital 领投,红杉资本和 Coatue 首次参加跟投,其余跟投的投资方包含 Addition、Betaworks 等 Hugging Face 原有的投资方。 ...

June 6, 2022 · 2 min · jiezi

关于emoji:编码乱码unicode-和-Emoji

概述在各种日志、tty 输入中,咱们总是可能发现各种编码不正确的字符。 �� `\xef\xbf\xbd\xf0\x9f\x98\xb8\xef\xbf\xbd`'\xe7\xb2\xbe\xe5\xa6\x99'`<<"你好">>`遇到这种状况,咱们下意识地会产生三个想法: 这是什么(本来的内容应该是什么)?从哪里来的?为什么会这样?我该怎么解决好?对于我集体的了解,乱码只不过是「一种对于文本类数据的谬误==解读==或者==展现==」。论断(造成的起因): 编码不当 encoding issue。比方,应用 utf8 编码的文本数据应用 gbk 解码。字体缺失 character missing in font。文本数据被谬误的截断 data was not properly splited。在网络传输或者贮存的时候被程序不失当的解决了。接下来,分享一下自己对于这些相干的问题整顿的信息。 筹备工作咱们以 Python3 为例,先学习一些简略且有必要的相干解决伎俩。 Python3 中用来解决字符的数据类型有以下: representtypeelement typelength'精妙'<class 'str'><class 'str'>2b'\xe7\xb2\xbe\xe5\xa6\x99'<class 'bytes'><class 'int'>6这个中央须要留神,'str' 中的每一个元素(element),py3 可不仅仅是range 256。请看: Python2: Python 2.7.18Traceback (most recent call last): File "<stdin>", line 1, in <module>ValueError: chr() arg not in range(256)Python3: Python 3.9.1>>> chr(0x70ce)'烎'能够很显著的看到,b'\xe7\xb2\xbe\xe5\xa6\x99' 这个长度为6的 bytes 就是精妙这两个汉字的 utf8 编码后二进制数据。它等价于bytes([0xe7, 0xb2, 0xbe, 0xe5, 0xa6, 0x99]])。 转换 bytes <-> str ...

December 8, 2021 · 2 min · jiezi

php-实现mysql存储支持emoji表情

最近一直在做微信公众号相关的需求,突然发现如果用户的昵称是emoji标签的话,这时候用户的昵称无法正常的存储到数据库中 一:原因: 这是由于Mysql的utf8编码最多3个字节,然而emoji标签的是4个字节,所以无法存储emoji标签信息,所以需要将数据的编码改成utf8mb4 二:解决: 1:设置连接编码 SET NAMES utf8mb4上面的命令相当于: SET character_set_client='utf8mb4';SET character_set_connection='utf8mb4';SET character_set_results='utf8mb4';2:设置数据库编码 ALTER DATABASE database_name(数据库名) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;3:设置表编码 ALTER TABLE table_name(表名) CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;设置如上编码之后在php连接数据时设置: 'charset' => 'utf8mb4',进行如上配置之后,这时候存储emoji标签时存储成功!!!

July 1, 2019 · 1 min · jiezi

PC端解析微信发送过来的emoji和在光标处插入emoji

最近公司的一个需求,需要在PC端接收并展示微信发送的消息,那么如何解析微信发送过来的表情?如何在编辑框光标出插入表情?本文将会详细的介绍如何解决这两个问题。一、PC端解析微信发送过来的emoji首先,我们知道,emoji的展示实际是图片的展示,input、textarea是没法展示图片的,所以我们用div里contenteditable=“true"属性,即可编辑。其次我们要了解,微信发送一个表情过来,后台数据库接收到的是/::-O这种特殊字符串,当然,如果是[微笑]这种字符串处理方式也一样,对照表可以参考微信默认表情代码和图片包,下载里面的图标到本地,并处理成如下格式页面展示表情,只需要遍历一下emoji数组,拼接一下图片的url即可。当要处理某个字符串里面的emoji时候,可遍历emoji数组,将后台接收的特殊字符串通过replace接口全局替换成对应的图片,反之,同样的方法将图片转化成微信可以解析成emoji的特殊字符,下面即是转换的函数 // 将特殊符号转成对应表情 config.imgUrl图片存放的url imgChangeEmoji(str) { emoji.forEach(element => { if (str && str.indexOf(element.code) > -1) { const effectCode = element.code.replace(/[.\[]{}()|^$?+]/g, ‘\$&’); // 转义字符串中的元字符 const pattern = new RegExp(effectCode, ‘g’); const imgUrl = &lt;img src='${config.imgUrl}/${element.img}'&gt;; str = str.replace(pattern, imgUrl); } }); return str; } // 将对话中的表情图片替换成特殊字符 config.imgUrl图片存放的url emojiChangeImg(str) { emoji.map(element => { if (str && str.indexOf(element.img) > -1) { const imgUrl = &lt;img src="${config.imgUrl}/${element.img}"&gt;; const pattern = new RegExp(imgUrl, ‘g’); str = str.replace(pattern, element.code); } }); return str; }需要特别注意的是,将特殊字符转成RegExp的时候,必须先用replace进行转义,即const effectCode = element.code.replace(/[.[]{}()|^$?+]/g, ‘\$&’); 手写转义是无效的。有了上面的解析函数,你只需在发送消息前执行emojiChangeImg(str)函数即可,同样的,如果想展示接收回来的消息,可以写个指令运行imgChangeEmoji(str)函数。二、光标处插入emoji在div添加keyup和click事件,如下代码(此处用的是angualr6) <div #editBox contenteditable=“true” (keyup)=“handleInputChange()” (click)=“handleClick()"></div>在handleInputChange()和handleClick()和函数里面设置最后光标对象 // 获取选定对象 const selection = getSelection(); // 设置最后光标对象 this.lastEditRange = selection.getRangeAt(0);选择emoji图片时创建一个img节点,并插入到最后光标位置,如下代码const img = new Image();img.src = ${config.imgUrl}/${emoji.img};const selection = getSelection();if (this.lastEditRange) { // 存在最后光标对象,选定对象清除所有光标并添加最后光标还原之前的状态 selection.removeAllRanges(); selection.addRange(this.lastEditRange);}// 选择第一选区const range = selection.getRangeAt(0);range.insertNode(img);range.collapse(false);即可在光标处插入img。想了解更多光标对象可参考html元素contenteditable属性如何定位光标和设置光标 ...

April 18, 2019 · 1 min · jiezi

关于字符编码你应该知道的事情

读完本文你将了解的知识点为什么 Windows 上使用 Notepad 会出现乱码为什么 Emoji 表情在有些手机上显示不准确为什么 Emoji 在没有做过特殊优化的数据库中存储失败为什么使用 Linux 开发的代码他人使用 Windows 开发后换行符全变了为什么在 JS 中 […’????????????????’] => ["????", “”, “????”, “”, “????”, “”, “????"]新版本 ECMAScript 针对 JavaScript 编码问题做了哪些改进为什么使用 Google Chrome 打开 JS 文件,文件中的中文字符会变成乱码比特、字节比特 ( Bit / Binary digit )缩写为 b,计算机最小的存储单位,以 0/1 来表示值字节 ( Byte )缩写为 B,8 个比特表示一个字节在计算机内部,所有的信息最终都表示为一个二进制的序列。每一个二进制位 ( Bit ) 有 0 和 1 两种状态,因此八个二进制位就可以组合出 256 种状态,这被称为一个字节 ( Byte ) ,也就是说,一个字节一共可以用来表示 256 种不同的状态或者符号。如果我们制作一张对应表格,对于每一个 8 位二进制序列,都对应唯一的一个符号。每一个状态对应一个符号,就是 256 个符号,从 0000 0000 到 1111 1111 。ASCII 与 EASCIIASCII (American Standard Code for Information Interchange,美国信息交换标准代码)1967 年发布,最后更新于 1986 年,共定义了 128 ( 2 ) 个字符( 0x00 - 0x7F ) ,其中 33 个字符为不可打印字符 ( 0x00 - 0x1F & 0x7F ),95 个可打印字符 ( 0x20 - 0x7E )可打印字符为标准键盘中可输入的字符,如下所示:10 个数字 ( 0-9 ),26×2 个大小写字母 ( a-z A-Z ) ,32 个标点符号 1 个空格 ( ,./;’[]-=!@#$%^&*()_+{}|:"<>? )ASCII 的局限在于只能显示 26 个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语,而其他携带类似于重音符号的字母无法显示 ( naïve、café )EASCII ( Extended ASCII,延伸美国标准信息交换码 )由于 ASCII 的天然不足,它的变种体迅速出现,兼容字符集对ASCII的处理ISO/IEC 646 1972年该标准来自数个国家标准,最主要的是美国的 ASCII 标准,ISO 646 为了表示欧洲各种语言的带附加符号( diacritical mark )的变音字母,由于没有码位空间去直接编码这些变音字母,所以用几个标点符号来兼作变音字母的附加符号ISO/IEC 8859扩展字符:0xA0 ( 160 ) - 0xFF ( 255 ) 淘汰了 ISO 646 编码标准 ISO 8859 统一了此前各国各语言的单独编码的混乱局面;废弃了 ISO 646 使用的退格键开始的转义序列来表示变音字母的方法,而是在 G1 区域直接编码表示变音字母。ISO 8859 有 15 个子版本( 1-11,13-16 ),其中囊括了大部分欧州语言,英语因为没有重音字母,所有可以使用其中任何一个子版本表示Microsoft Codepage 1252 为 ISO 8859-1 的超集,扩充了 0x80 - 0x9F 来编码一些可打印字符 ( ‚ ƒ „ … † ‡ ‰ Š ‹ Œ Ž ‘ ’ “ ” • – — ™ š › œ ž Ÿ )例如在中国 GB/T 1988-80 标准中: $ u+0024 替换为 ¥ u+00A5 , u+007E 替换为 ‾ u+203EANSIWindows 操作系统上的 ANSI 编码并不是指的是美国国家标准学会 ( ANSI ),而是用来指称多个不同的代码页,比如在简体中文编码操作系统中,ANSI 实际使用 GB 系字符编码中文GB2312 ( 1981 ) 6763 个汉字,最初版本,双字节编码GB12345 ( 1993 ) 6866 个汉字,为了适应繁体汉字信息处理而制定的标准GBK ( 1995 ) 21886个汉字和图形符号,不属于国家标准GB18030 ( 2000 ),70244 个字符,基于 GBK,现行版本国际通用标准Unicode ( 万国码、国际码、统一码、单一码 )最初版本:1.0.0 发布,1991 年 10 月发布,7161 个字符当前正式版本 Unicode 11.0 ( 2018 年 6 月 ) 拥有 137374 个字符当前最新版本:Emoji 12.0 Beta表示方法:基本平面:通常会用 “U+” 然后紧接着 4 个 16 进制的数字来表示这一个字,可表示 6 万余个字符其他平面使用 “U-” 然后接着 8 个 16 进制数字表示ISO/IEC 10646 ( UCS / 通用字符集 )该字符集包括了其他所有字符集,保证了与其他字符集的双向兼容,ISO 10646 有三种实现级别,不同的实现级别能支持的字符数量不同与 Unicode 的关系:所有字符在相同位置且有相同名字Unicode 标准里有详细说明某些语言和文字的表达算法等ISO 承诺,ISO 10646 将不会替超出 U+10FFFF( Unicode 编码以 U+ 开头) 的 UCS-4 编码赋值UTF ( Unicode Transformation Format )Unicode 是一个字符集,其实现方式称为 Unicode 转换格式,即 UTFUTF-32Unicode 与 UCS 合并之前已经产生了 UCS-4 编码方式,UCS-4 使用了 32 位来表示每个编码,为了兼容 Unicode 产生了 UTF-32 标准,编码空间限制在了 0x000000 - 0x10FFFF 之间,因此可以说 UTF-32 是 UCS-4 的子集。由于 UTF-32 的编码空间占用过大,因此在 HTML5 标准中明确规定不能使用 UTF-32 进行编码UTF-16UTF-16 编码拥有定长和变长两个编码特点,对于 Unicode 基本平面的字符,UTF-16 占用两个字节,对于辅助平面的字符,UTF-16 编码占用四个字节Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做 “零宽度非换行空格 ( zero width no-break space )”,用 FE FF 表示。但在不同计算机系统中对字节顺序的理解是不一致的,即出现了大端序 ( UTF-16 BE ) 与小端序 ( UTF-16 LE ) 两种情况。文本头部使用 FE FF 与 FF FE 进行区分,此区分符称为“字节顺序标记 ( BOM ) ”如何确定双字节和四字节:在基本平面内,从 U+D800 到 U+DFFF 是一个空段,不对应任何码点,这个空段用来映射辅助平面的字符,即一个辅助平面的字符,被拆成两个基本平面的字符表示。例如: ???? 可以表示为 U+D83D U+DC68UTF-8由于前两种编码方式的编码规则对与英语国家来说非常浪费(2-4 字节编码)UTF-8 当前使用 1-6 个字节为每个字符编码对于单字节的符号,字节的第一位设为 0 ,后面 7 位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。对于n字节的符号( n > 1 ),第一个字节的前n位都设为 1,第 n + 1 位设为0,后面字节的前两位一律设为 10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码 ( Unicode 范围由 U+0080 至 U+07FF )。其他基本多文种平面 ( BMP ) 中的字符(这包含了大部分常用字,如大部分的汉字)使用三个字节编码 ( Unicode范围由U+0800至U+FFFF )。其他极少使用的 Unicode 辅助平面的字符使用 4-6 字节编码UCS-2JavaScript 采用了 Unicode 字符集。但是只支持一种编码方式。JS 最先采用的编码既不是 UTF-16 也不是 UTF-32 或 UTF-8 ,而是 UCS-2 。UTF-16 明确宣布是 UCS-2 的超集。UTF-16 中基本平面字符延用 UCS-2 编码。辅助平面字符定义了 4 个字节的表示方法。JS 只能处理 UCS-2 编码,造成所有字符在这门语言中都是两个字节,如果是四个字节的字符。会被当做两个双字节的字符处理。两者的关系简单说,就是 UTF-16 取代了 UCS-2,或者说 UCS-2 整合进了 UTF-16。所以,现在只有 UTF-16,没有 UCS-2。码点和平面字符会从 0 开始为每个字符指定一个编码, 这个编码叫做码点举例Unicode 中给字符进行分区定义,每个区称为一个面,Unicode 拥有 0-16 共 17 个平面,每个平面 16 个字符平面字符值描述0号平面U+0000 - U+FFFF基本多文种平面1号平面U+10000 - U+1FFFF多文种补充平面2号平面U+20000 - U+2FFFF表意文字补充平面3号平面U+30000 - U+3FFFF表意文字第三平面(未正式使用)4 - 13号平面U+40000 - U+DFFFF(尚未使用)14号平面U+E0000 - U+EFFFF特别用途补充平面15号平面U+F0000 - U+FFFFF保留作为私人使用区(A区)16号平面U+100000 - U+10FFFF保留作为私人使用区(B区)题首问题为什么 Windows 上使用 Notepad 会出现乱码Windows 上的 Notepad 软件在保存文件时默认使用的是 ANSI 编码保存,而在打开的时候需要猜测 txt 文件的编码方式,如果文档中出现了 ANSI 编码以外的字符,则在打开时候可能会出现编码识别错误的情况,由于 txt 文件为纯文本文件,没有保存文档编码信息的区域,则此问题可能一直存在。解决该问题可在保存文件的时候使用 UTF-8 编码保存,但需要注意的是:Windows 的 Notepad 应用使用 UTF-8 保存的时候实际使用的为 UTF-8 BOM 方式,其表现为在文本最开头添加 EF BB BF ,这部分称为 UTF-8 字节顺序标记 ,该方式并非强制标准,如果在代码文件中使用该方式保存则有可能出现运行错误。为什么 Emoji 表情在有些手机上显示不准确当前 iOS 12 使用的 Unicode 版本为 11,而大众使用比较的 Android 8.0 使用的Unicode 版本为 9,如果在 Android 系统中出现了新版本的字符,则会出现无法显示或显示错误的情况。例如在 Unicode 8.0 中加入了 5 个菲茨帕特里克修饰符,用来调节人形表情的肤色,如果在低于此版本的 Unicode 中显示的字符为两个字符,分别是颜色加人偶。另外 Unicode 新版本中使用 U+200D 零宽连字 ( ZWJ ) 将多个 Emoji 连起来,例如 ???????????????? => ????????????????为什么 Emoji 在没有做过特殊优化的数据库中存储失败Emoji 表情占用 4 个字节,但是 MySQL 数据库使用的 utf-8 默认编码最多只能存储 3 个字节 ( UTF-8 标准支持最长编码为 6 字节 ),就会导致存储不进去,在读取的时候读取不完整,导致乱码修复方法为:修改数据库字符集为 uft8mb4,如果数据库连接池中对字符集作出了设置需要在链接中去掉 characterEncoding 参数为什么使用 Linux 开发的代码他人使用 Windows 开发后换行符全变了Windows 系列系统使用的换行标志为 CRLF,该换行标志与 Unix/Linux 的 LF 换行及 macOS 的 CR 换行不相同。如果在代码工程中使用了 Code Lint 工具自动格式化,可能会使代码中的 LF 换行自动转换为 CRLF 换行,Git 中也能捕获或忽略这个变化。另外,从 Windows 10 1803 开始,支持 Unix/Linux 的 LF 换行及 macOS 的 CR 换行。为什么在 JS 中 […’????????????????’] => [”????", “”, “????”, “”, “????”, “”, “????”]???????????????? 是 2015 年添加到 Emoji 2.0 中的新字符,使用 U+200D 零宽连字 (ZWJ) 将4个 Emoji 连起来,可使用以下代码检测[…’????????????????’].forEach(e=>{console.log(e.codePointAt().toString(16))})新版本 ECMAScript 针对 JavaScript 编码问题做了哪些改进由于 JavaScript 使用的是只支持双字节编码的 USC-2 编码方式,所以所有超过二字节编码的 Unicode 字符都无法在 JavaScript 中处理例如 ‘????’.charCodeAt().toString(16) 输出的结果为 d83d ,而????的Unicode 码点却不是 d83d,造成这样的原因为 JavaScript 只处理了该字符的前两个字节为了解决这些问题,ECMAScript 6 种增强了对新版本 Unicode 的支持。例如:for of 循环中对双字节以上字符能识别正确长度Array.from 等方法能正确划分字符串支持直接使用码点表示字符,例如’\ud83d\udc68’ === ‘????’ === ‘\u{1F468}‘String.fromCodePoint() 和 String.prototype.codePointAt() 等方法代替 String.fromCharCode() 和String.prototype.charCodeAt() 等方法,以用于支持 UTF-16 编码字符正则表达式提供了 u 修饰符,对正则表达式添加4字节码点的支持提供了normalize方法,允许"Unicode正规化" ,例如:’\u01D1’.normalize() === ‘\u004F\u030C’.normalize() 为什么使用 Google Chrome 打开 JS 文件,文件中的中文字符会变成乱码由于 2017 年更新的某版本 Chrome 中,去除了对 JS 文件默认编码 UTF-8 的支持,使用了系统默认编码(例如中文操作系统使用 GB18030 )对 JS 文件的解码,所以导致 JS 文件中的中文字符变成乱码。解决方法有两种:在文件服务器中对返回头的 Content-Type 设置加上 charset=UTF-8浏览器中使用插件改变网页编码方式,例如使用 FEHelper 工具参考资料:WikiPediaUnicode与JavaScript详解 - ruanyifeng一个表情引发的思考 - JDC「记事本」程序的BUG? - 知乎解决Emoji存储MySQL乱码问题本文首发地址blog.shoyuf.top第二次在 segmentfault 上发文章,欢迎各位评论区中吐槽指正 ...

February 19, 2019 · 4 min · jiezi

解析带emoji和链接的聊天系统消息

在写聊天系统的时候,不可避免地要对聊天系统中的消息做一些解析常见的比如一句话中带有emoji、link等信息的时候,要把emoji解析成图片、把link转成可以点击的(项目中没有做对图片做行内处理,而是把图片像微信一样作为单独消息发送)我们知道react的标签都是jsx的,所以在解析消息的时候,就必须在得到消息内容的时候,就先把消息内容分段截取比如这样一则消息今天吃饭了吗?[emoji]我还没吃呢[emoji],给你个链接看看吧!http://www.google.com/emoji要解析成图片,http://www.google.com/ 要解析成可以点击的链接,之间的文字要解析成文本jquery时代,只需要使用正则匹配emoji,替换成图片,用正则匹配链接,替换成a标签即可但是在react里,这三者对应的是不同的jsx标签。所以必须把文本解析成分段式的思路:上面这句话,可以解析成6部分part1: 今天吃饭了吗?part2: [emoji]part3: 我还没吃呢part4: [emoji]part5: ,给你个链接看看吧!part6: http://www.google.com/每部分对应使用不同的jsx标签第一步,我们先使用正则匹配emoji和链接分别的正则如下(匹配链接应该有更优秀的正则)var emojiregex = new RegExp(/\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff]/g, ‘g’); // 匹配emoji字符var matchUrlRegex = new RegExp(/(https?:)//([^/]+)(/[^?])?(?[^#])?(#.)?/g,‘g’); // 匹配url的正则var emojiRegArray = text.match(emojiregex); // 匹配了所有的emoji的词var urlRegArray = text.match(matchUrlRegex);得到两个数组,分别是匹配到的emoji和匹配到的url第二步,使用index()方法,获取每个emoji、url的位置、长度,并记录 var indexEmojiArray = []; // 记录表情的位置、内容的数组 var indexUrlArray = []; // 记录链接的位置、内容的数组 var pos1 = -1, pos2 = -1;//头 if(emojiRegArray){ for (let i = 0; i < emojiRegArray.length; i++) { pos1 = text.indexOf(emojiRegArray[i], pos1 + 1); indexEmojiArray.push({ type: 1, // type为1表示是表情 pos: pos1, length: emojiRegArray[i].length, res: emojiRegArray[i], }); } } if(urlRegArray){ for (let i = 0; i < urlRegArray.length; i++) { pos2 = text.indexOf(urlRegArray[i], pos2 + 1); indexUrlArray.push({ type: 3, // type为1表示是url pos: pos2, length: urlRegArray[i].length, res: urlRegArray[i], }); } } 第三步,按照这些元素在消息中的位置,两个数组合并成一个数组 // 合并两个数组 var indexArray = []; // 以上两个数组按照pos顺序合并的数组 if(emojiRegArray && urlRegArray){ let point1 = 0,point2 = 0; while(point1 < indexEmojiArray.length || point2 < indexUrlArray.length){ if(!indexEmojiArray[point1]){ // emoji加完了 indexArray.push(indexUrlArray[point2]); point2++; }else if(!indexUrlArray[point2]){// url加完了 indexArray.push(indexEmojiArray[point1]); point1++; }else{ // 两个都没加完 if(indexEmojiArray[point1].pos < indexUrlArray[point2].pos){ indexArray.push(indexEmojiArray[point1]); point1++; }else{ indexArray.push(indexUrlArray[point2]); point2++; } } } }else if(emojiRegArray && !urlRegArray){ // 有emoji没有url indexArray = indexEmojiArray; }else if(!emojiRegArray && urlRegArray){ // 有url没有emoji indexArray = indexUrlArray; }第四步现在,我们得到了一个indexArray,存储了emoji和url的位置和长度的数组现在我们要把文本也加进去,并且,emoji替换成图片// 这里开始把indexArray加工成contentArray let contentArray = []; let point = 0; // 记录当前指针位置 for (let i = 0; i < indexArray.length; i++) { // 把这一项和上一项之间的内容push成文本 console.log(point); let textContent = text.substr(point, indexArray[i].pos-point); console.log(textContent); contentArray.push({type: 0, content: textContent}); // point += textContent.length; if(indexArray[i].type === 1){ // 如果这一项是emoji // contentArray.push({ type: 1, “resources”: EMOJI_MAP[indexArray[i].res] || [] }); contentArray.push({ type: 1, resources: indexArray[i].res || [] }); point = indexArray[i].pos + indexArray[i].length; }else if(indexArray[i].type === 3){ // 如果这一项是url contentArray.push({ type: 3, url: indexArray[i].res}); point = indexArray[i].pos + indexArray[i].length; } } // 加入末尾项。如果indexArray为空,那么末尾项就是唯一的文本项 let lastPrevItemIndex = (indexArray[indexArray.length-1] ? indexArray[indexArray.length-1].pos+indexArray[indexArray.length-1].length : 0); contentArray.push({type: 0, content: text.substr(lastPrevItemIndex, text.length)});最后得到的contentArray我们return出去。比较难的部分在第四步,思路是,我们使用一个指针,对消息做解析,一开始指针的位置为0开头不管如何都push一个文本对象进入contentArray中直到遇到emoji或者url位置为止比如遇到的是emoji,我们把emoji解析成对象push到contentArray中,然后指针加上emoji的长度最后加上末尾。如果末尾不为文本,也添加一个空的文本对象。完毕。下面附上所有代码let stringToContentArray = function (text) { var emojiregex = new RegExp(/\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff]/g, ‘g’); var matchUrlRegex = new RegExp(/(https?:)//([^/]+)(/[^?])?(?[^#])?(#.)?/g,‘g’); // 匹配url的正则 var contentArray = []; if (!text) { // 没有内容 contentArray.push({ type: 0, “content”: ‘[无内容消息]’ }); return contentArray; } var emojiRegArray = text.match(emojiregex); // 匹配了所有的emoji的词 var urlRegArray = text.match(matchUrlRegex); // console.log(text); console.log(’emojiRegArray:’,emojiRegArray); console.log(‘urlRegArray:’,urlRegArray); if (emojiRegArray === null && urlRegArray === null) { // 没有emoji表情, 也没有链接 contentArray.push({ type: 0, “content”: text }); return contentArray; } var indexEmojiArray = []; // 记录表情的位置、内容的数组 var indexUrlArray = []; // 记录链接的位置、内容的数组 var indexArray = []; // 以上两个数组按照pos顺序合并的数组 var pos1 = -1, pos2 = -1;//头 if(emojiRegArray){ for (let i = 0; i < emojiRegArray.length; i++) { pos1 = text.indexOf(emojiRegArray[i], pos1 + 1); indexEmojiArray.push({ type: 1, // type为1表示是表情 pos: pos1, length: emojiRegArray[i].length, res: emojiRegArray[i], }); } } if(urlRegArray){ for (let i = 0; i < urlRegArray.length; i++) { pos2 = text.indexOf(urlRegArray[i], pos2 + 1); indexUrlArray.push({ type: 3, // type为1表示是url pos: pos2, length: urlRegArray[i].length, res: urlRegArray[i], }); } } if(emojiRegArray && urlRegArray){ let point1 = 0,point2 = 0; while(point1 < indexEmojiArray.length || point2 < indexUrlArray.length){ if(!indexEmojiArray[point1]){ // emoji加完了 indexArray.push(indexUrlArray[point2]); point2++; }else if(!indexUrlArray[point2]){// url加完了 indexArray.push(indexEmojiArray[point1]); point1++; }else{ // 两个都没加完 if(indexEmojiArray[point1].pos < indexUrlArray[point2].pos){ indexArray.push(indexEmojiArray[point1]); point1++; }else{ indexArray.push(indexUrlArray[point2]); point2++; } } } }else if(emojiRegArray && !urlRegArray){ // 有emoji没有url indexArray = indexEmojiArray; }else if(!emojiRegArray && urlRegArray){ // 有url没有emoji indexArray = indexUrlArray; } console.log(“indexArray: “, indexArray); // 这里开始把indexArray加工成contentArray let point = 0; // 记录当前指针位置 for (let i = 0; i < indexArray.length; i++) { // 把这一项和上一项之间的内容push成文本 console.log(point); let textContent = text.substr(point, indexArray[i].pos-point); console.log(textContent); contentArray.push({type: 0, content: textContent}); // point += textContent.length; if(indexArray[i].type === 1){ // 如果这一项是emoji // contentArray.push({ type: 1, “resources”: EMOJI_MAP[indexArray[i].res] || [] }); contentArray.push({ type: 1, resources: indexArray[i].res || [] }); point = indexArray[i].pos + indexArray[i].length; }else if(indexArray[i].type === 3){ // 如果这一项是url contentArray.push({ type: 3, url: indexArray[i].res}); point = indexArray[i].pos + indexArray[i].length; } } // 加入末尾项。如果indexArray为空,那么末尾项就是唯一的文本项 let lastPrevItemIndex = (indexArray[indexArray.length-1] ? indexArray[indexArray.length-1].pos+indexArray[indexArray.length-1].length : 0); contentArray.push({type: 0, content: text.substr(lastPrevItemIndex, text.length)}); return contentArray;} ...

January 31, 2019 · 3 min · jiezi