在做独立博客的时候,特别是对于程序员来说,代码高亮是很重要的一个组件。我也接触过几款不同的代码高亮引擎。衡量一个高亮引擎的好坏有很多不同的方面:分词、性能、稳定性、主题丰富性。本文将专注分词的表现,对几款流行的高亮引擎以及 IDE 做一个横向对比。

什么是分词

要把一段代码高亮输出,主要工作流程大概如下:

image-20201208104533768

分词的过程就类似于画画的线稿,线稿越精细,上色的自由度就越高,最终得到的输出就有可能越丰富好看。作为一个面向颜值的工程师,对颜值可以说非常看重了。不管着色主题好看与否,分词的精细程度才是关键之处。分词分好了,怎么上色无非是主题作者的事情。

对比的对象

测试例子代码是 Python,因为我也主要关注 Python 代码的分词表现,主题统一用 Monokai 并做了微调以求尽量统一。根据分词进行在前端或者后端,本次参加对比的选手有:

  • 前端分词:Highlight.js, Prism.js,送到 HTML 中的是未标注的代码段
  • Python 后端分词:Pygments, 送到 HTML 中的是已标注的代码段

另外请到了几位大佬下场指导:他们分别是编辑器界扛把子 Vim、GUI 编辑器扛把子 VSCode,以及专用 IDE 扛把子 PyCharm(没有人比我更懂 Python 分词)。 他们仅作为天花板的参考。编辑器都尽量用最简单的配置,禁用多余的扩展。

对比结果

废话少说,我拉了一个清单,把例子代码中涉及到的语法元素做了大概的总结,渲染结果可以在这里查看。

Highlight.js Prism.js Pygments Vim VSCode PyCharm
区分 built-in ✔️1 ✔️ ✔️ ✔️ ✔️ ✔️
识别 operator ✔️ ✔️ ✔️ ✔️
区分 import keywords ✔️ ✔️ ✔️
区分 magic method ✔️ ✔️
区分 doc-string 与 string ✔️ ✔️ ✔️ ✔️
解析 f-string ✔️2 ✔️ ✔️ ✔️ ✔️
解析 decorator ✔️2 ✔️ ✔️ ✔️2 ✔️ ✔️
区分参数与 identifier ✔️ ✔️
区分 self 与参数 ✔️ ✔️
区分 class 与 identifier ✔️ ✔️ ✔️ ✔️ ✔️
区分 annotation3 ✔️

总结

我们可以看到三个对比者中 Prism.js 和 Pygments 不相上下,Prism.js 只差一点,但 Pygments 毕竟是 Python 实现所以可以理解。最差的是 Highlight.js,综合网上评价的 bug 比较多的情况,不建议选择。

用前端分词的好处是配置简单,只需要额外几个 script 就完成。用 Pygments 则需要对后端代码做适当改动。不过python-markdownMarko都提供了对应的扩展,可以在 Markdown 转换 HTML 的时候就通过 Pygments 标注好代码段,这也不是很大的问题。考虑到 Prism.js 已经能有比较好的表现了,我首推 Prism.js 做博客的代码高亮。

而三个产品距离专业的代码编辑器都还有很大的距离。至于 Vim,因为我不会用或者不会配,可能会有更好的表现,希望懂的同学补充。


  1. Highlight.js 很奇怪,int, object能识别,但float却没有

  2. 整体识别,而没有细致分词

  3. 只是一个例子,PyCharm 还有很多其他独有的分词元素