初级字典树查找在 Emoji、关键字检索上的运用 Part-3
系列索引
生产实践
我们最终要解决 Emoji 在浏览器和打印物上的显示一致。
进行了多番对比,,在显示效果和精度上,macOS 和 Unicode 标准的风格相近,最终决定使用 Unicode 提供的图片作为跨平台显示。
浏览器和渲染程序在渲染文本前,将内容交由后端进行 Emoji 检索。
提交请求示例如下:
{
"sections":[
"颠簸了三小时飞机✈️➕两小时公交地铁🚇➕四小时大巴➕一小时🚢 终于到了我们的目的地像面粉一样的沙滩和碧绿的大海 这就是我们第一次旅行的地方in沙美岛🏖"
]
}
后端使用了 MongoDB 存储了所有 Emoji 的 base64 表示,检索到 Emoji 字符后输出替换内容。
{
"sections": [
"颠簸了三小时飞机[chuye-emoji://1835]️[chuye-emoji://2263]两小时公交地铁[chuye-emoji://1792][chuye-emoji://2263]四小时大巴[chuye-emoji://2263]一小时[chuye-emoji://1834] 终于到了我们的目的地像面粉一样的沙滩和碧绿的大海 这就是我们第一次旅行的地方in沙美岛[chuye-emoji://1734]"
],
"regExp": "\\[chuye\\-emoji:\\/\\/(\\d+)\\]",
"images": {
"1734": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAMAAADQmBKKAAAABGdBTUEAALGPC...",
"1792": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAMAAADQmBKKAAAABGdBTUEAALGPC...",
"1834": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAMAAADQmBKKAAAABGdBTUEAALGPC...",
"1835": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAMAAADQmBKKAAAABGdBTUEAALGPC...",
"2263": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABEBAMAAADQAW4PAAAABGdBTUEAALGPC..."
},
"emojis": {
"1734": "🏖",
"1792": "🚇",
"1834": "🚢",
"1835": "✈",
"2263": "➕"
}
}
移除了
base64
后面的更多内容,只起示例作用。
返回内容包含以下字段
字段 | 类型 | |
---|---|---|
sections | 字符串数组 | 替换 Emoji 后的字符串输出 |
regExp | 字符串 | 辅助定位 Emoji表达式 的正则表达式 |
images | 字典/对象 | 所有Emoji 表达式 的base64 编码表示 |
示例请求包含了5个 emoji 字符,后端将它们一一替换成了所谓的emoji 表达式,依次为 [chuye-emoji://1734], [chuye-emoji://1792], [chuye-emoji://1834], [chuye-emoji://1835], [chuye-emoji://2263]
。
Emoji 表达式:作者自己的定义,表示一段 emoji ,固定格式形如
[chuye-emoji://1734]
,尾部的数字是序号。整个表达式可以用响应携带的正则表达式regExp
字段匹配。
浏览器在拿到响应后, 使用正则定位该表达式, 再替换其为 <img class="emoji" />
标签并应用响应中的 base64 资源,最后将文本当作 HTML 输出即可。演示代码:
let req = {sections: ["..."]};
let resp = // POST req to service and get response
let regExp = new RegExp(resp.regExp, 'g');
let replacments = [];
for (let section of resp.sections) {
let replacment = section.replace(regExp, (...args) => {
let id = args[1];
let src = resp.images[id];
return `<img class="emoji" src="${src}" title="${id}" />`
});
replacments.push(replacment);
}
//do stuff with replacments
简化 base64 后的输出内容是文本和 img
标签混合的 html 内容。
emoji
style 的定义如下(引用自 Twitter 方案, 并未精确测试)
img.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
使用 base64 而不是将资源扔到 CDN 上, 还是基于现有状况进行的测试.
我们的打印物可能包含10-20个 emoji 字符,将对应的 base64 合并在响应中,大小在100k左右,再放大2倍也可以接受。
- 如果替代以16个 URL 资源,请求成本就非常夸张了;
- 合并图片的做法虽然可以减少 HTTP 请求,但成倍地放大了解决方案复杂度;