在博客中使用 BibTeX

8 月 19 日更新:一些关于 a11y 和排版方式的 内容 已经变化。20 日更新:加入了 新样式

在博客中使用 BibTeX 的需求起源于一些需要引用文献的博文。例如之前的 NC¹ 属性加密 KW19,那时候我是手工格式化参考文献的。当然,能自动化就不要手工去做,于是几个月前开始了 BibTeX-TS——TypeScript 写的 BibTeX 解析器。现在设施已经足够完备,我可以把 alpha.bst 的实现近似翻译到 JavaScript 里,成为博客构建系统的一部分。位图版的题图(BibTeX 徽标)衍生自 Wikimedia Commons

BibTeX-TS 和博客工具链

BibTeX-TS 的需求脱胎于我对 blogging 工具链的要求,不过它是一个一般向的项目。主要功能是把 .bib 文件解析为结构化的对象并加以操作。

整个过程花了几个月,从西雅图到北京,我在研究的空余时间(或者说研究累了需要换换脑筋)慢慢完成。中间有两次推倒重来的过程:第一次没有记录在 git 的历史里,第二次可以在 git 的历史中找到。

在西雅图的时候主要写了基本对象模型、解析器和 BST 语言的基本函数(例如 purify$ 用于清理字符串、format.name$ 用于格式化名字),几个比较有意思的:

  • 由于面向对象的引入,一些 BST 函数被分成了几步,譬如 format.name$ 本来是接受两个字符串和一个整数(一堆名字、一个名字格式和第几个名字)输出一个字符串(格式化好的那个名字),在 BibTeX-TS 里分成把字符串解析成名字、把字符串解析成名字格式、用名字格式格式化名字三部分。
  • 我发现了一个新的写 parser 的模式——用下一个状态转移的委托(函数指针)表示状态,例如 .bib 解析器 就是这样写出来的。
  • 我看了很多遍 Déc07Mar09,这两篇文档详尽地解释了 BibTeX 的细节(比 bibtex.org 清楚多了)。很多细节都是值得注意的,还有一部分细节是过时的(例如 purify$ 也会删除所有非 ASCII 字符,这对汉语文献非常不友好,虽然可能并不需要引用很多汉语文献),我希望和原版尽量接近,但也有选择性。

在北京做的部分是实现简易 TeX 渲染框架并实例化框架、着手翻译 alpha.bst 的实现(我翻译的方法就是盯着它并把它的每个类型的渲染函数翻译一遍;实际上很容易写一个 BST 解析器和解释器,毕竟基础设施已经有了,而且 BST 是一个非常容易模拟的语言),见于 (当然这个实现和 alpha.bst 是有出入的,例如我没有对文章标题做 title case 转换,因为很多人根本不会写 BibTeX 文件,按照 alpha.bst 的程序渲染出来的结果乱七八糟)。还有就是(我已经轻车熟路的)实现 BibTeX-TS 和博客工具链之间的胶水,以及稍微更新一下实现用 Markdown 行内代码 `cite:key1,key2` 语法做文内引用、用代码块 ```blog-bib 语法做 BibTeX 渲染,以及把锚记跳转 hook 起来。

整个过程的结果就是我的博客以后可以用 BibTeX 自动格式化参考文献,以及手有点抽筋

例子

本文本身就是一个例子,文中的 BibTeX 都可以直接从官网复制而不加修改(当然我实际上修改了一些让渲染结果更适合 Web)。几个有意思的特性:

  • 所有的功能都是静态的,客户端不需要 JavaScript。
  • 支持 crossref 交叉引用(这是标准样式的一部分),作为引用文章描述文字的 TeX 代码中包含的 \cite 也会被处理,例如 KW19 的描述文字里有一个对 IR19 的引用。
  • 多次引用同一篇文章,每次的引用都有自己的身份,因此点击引用的链接后可以通过“三角形”链接重新回到正确的位置。例如 Dam92Dam92
  • 可以一次引用多篇文章,例如 GSW13QWW18CDG⁺17
  • 可以用 BibTeX 代码里的 @string{ space = ... } 字符串控制一次引用多篇文章时逗点后面的空格的宽度(默认 thin,还可以选 normalnone)。
  • 除了 space 字符串,还有如下样式参数:
    • bst 可以选择使用哪个样式来渲染,最初的版本支持 alpha8 月 20 日增加了 plainabbrv(例如 Blogging my blog 的例子 就使用了该样式),后续计划增加 acmapalikesiam
    • comma 可以选择 `cite:key1,key2` 的分隔符是逗点(,)还是分号(;)。
    • brackets 可以选择 `cite:key` 两侧是中括号([])还是小括号(())。
    • nickname 可以选择 ```blog-bib 输出文章昵称是用中括号([])、小括号(())包裹还是无括号后加句点(.),又或者是和 `cite:key` 保持一致(cite)。
    • 不同的 bst 下,commabracketsnickname 的默认值可能不同。
  • 为了支持汉语文章的渲染,我添加了两个新的 TeX 控制序列 \nickname\zhCN。前者只有在渲染文章昵称(首字母)时才渲染当前分组内的后续内容,否则不渲染;后者把该分组内后续内容渲染为带有汉语语言标记的 HTML。如果作者名字写 {\nickname L}{\nickname i}{\nickname}{\nickname\bgroup}{ }{\egroup\egroup\bgroup\zhCN 李雷},则渲染结果是 Li19。前面三个 \nickname 控制序列是为了确保提取文章昵称的时候得到 Li,后面通过巧妙的组合使得 purify$ 整个字符串的时候得到的是 Li 李雷(最长的拼音音节可以有 6 个字符,对齐是为了排序),并且通过 \nickname 控制序列确保 Li 不会被渲染。
  • 如果你在 LaTeX 里 \cite{key1,key2} 且选择逗点后不加空格,则 LaTeX 似乎不允许在一个 \cite 控制序列产生的中括号内换行(至少 LLNCS 是这样的),我觉得必要时逗点后换行比较合理。这个问题和逗点后没有空格是联动的,大概是 LaTeX 认为没有后面空格的逗点是小数(逗)点,所以禁止换行——然而这在一些情况下的排版结果简直惨不忍睹。
    • LaTeX 里的解决方法是在 , 后面加上 \hspace{0pt}
    • 在我的 blog 里,为了解决上面这个问题,同时为了更好的 accessibility,我把 [,] 包裹在 span 里,并且设置 aria-hidden="true",且在逗点的 span 里放置一个内部是空格的 span,它的字体大小由需要的空格的大小控制。这篇文章选择的空格样式是“无空格”,实际的实现里是有一个字号为 0 的空格。举个例子:“Gro11DLO⁺18。”按照简体中文排版规则外加“允许引用内逗点后断行”,前面这句话可以断行的地方是:“举”“个”“例”周围、冒号后、逗点后、右引号后。
    • 有趣的实际评测:Edge 44.17763.1.0、Safari for iOS 12.4、Safari for macOS 10.14.6、Chrome 73.0.3683.103 for Windows (x64) 似乎都认为冒号后、右引号后不可以断行;Chrome 76.0.3809.100 for Windows (x64) 允许冒号后、右引号后断行。
  • 一个美中不足的地方是每个 `cite:key` 产生的 a 标签的 ID 是依据“这是第几次 cite 这个 key”产生的,这导致文章修改后链接的 ID 可能变化,对书签不友好。这是技术难度、书写难度和效果之间的权衡——要么我需要人工智能来指定一个比较稳定的 ID,要么我需要每次手工指定 ID(这太麻烦了),要么我选择放弃书签稳定性。我选择了放弃书签稳定性。
  • 除了 Li19,这篇文章用到的例子文献都是我读过的😄。

References

Here’s the list of references (this sentence is rendered using @preamble{ ... }).
CDG⁺17 Chongwon Cho, Nico Döttling, Sanjam Garg, Divya Gupta, Peihan Miao, and Antigoni Polychroniadou. Laconic Oblivious Transfer and its Applications. Cryptology ePrint Archive, Report 2017/491, 2017. https://eprint.iacr.org/2017/491.
Dam92 Ivan Damgård. Towards Practical Public Key Systems Secure Against Chosen Ciphertext attacks. In Joan Feigenbaum, editor, Advances in Cryptology — CRYPTO ’91, pages 445–456, Berlin, Heidelberg, 1992. Springer Berlin Heidelberg.
Déc07 Xavier Décoret. A summary of . Online, 2007.
DLO⁺18 Ivan Damgård, Ji Luo, Sabine Oechsner, Peter Scholl, and Mark Simkin. Compact Zero-Knowledge Proofs of Small Hamming Weight. In Michel Abdalla and Ricardo Dahab, editors, Public-Key Cryptography – PKC 2018, pages 530–560, Cham, 2018. Springer International Publishing.
Gro11 D. Gross. Recovering Low-Rank Matrices From Few Coefficients in Any Basis. IEEE Transactions on Information Theory, 57(3):1548–1566, March 2011.
GSW13 Craig Gentry, Amit Sahai, and Brent Waters. Homomorphic Encryption from Learning with Errors: Conceptually-Simpler, Asymptotically-Faster, Attribute-Based. Cryptology ePrint Archive, Report 2013/340, 2013. https://eprint.iacr.org/2013/340.
IR19 Yuval Ishai and Vincent Rijmen, editors. Advances in Cryptology - EUROCRYPT 2019 - 38th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Darmstadt, Germany, May 19-23, 2019, Proceedings, Part I, volume 11476 of Lecture Notes in Computer Science, Springer, 2019.
KW19 Lucas Kowalczyk and Hoeteck Wee. Compact Adaptively Secure ABE for from -Lin. In Advances in Cryptology - EUROCRYPT 2019 - 38th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Darmstadt, Germany, May 19-23, 2019, Proceedings, Part I IR19, pages 3–33.
Li19 李雷. 一个例子. August 2019. 这是一个虚构的参考文献.
Mar09 Nicolas Markey. Tame the BeaST, 2009. See CTAN package and PDF.
QWW18 Willy Quach, Hoeteck Wee, and Daniel Wichs. Laconic Function Evaluation and Applications. Cryptology ePrint Archive, Report 2018/409, 2018. https://eprint.iacr.org/2018/409.

请启用 JavaScript 来查看由 Disqus 驱动的评论。