初级字典树查找在 Emoji、关键字检索上的运用 Part-3

系列索引

  1. Unicode 与 Emoji
  2. 字典树 TrieTree 与性能测试
  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 请求,但成倍地放大了解决方案复杂度;

posted @ 2018-09-03 09:12  Jusfr  阅读(533)  评论(0编辑  收藏  举报