- 科研
【免费下载链接】zotero-better-bibtex
Make Zotero effective for us LaTeX holdouts
导读
Zotero 的标准字段有时无法容纳你希望出现在导出条目中的全部信息(例如法律法规的court、专利申请的assignee、或任意自定义 LaTeX 字段)。本文基于 Better BibTeX 官方文档 site/content/exporting/extra-fields.md,系统讲解如何利用 Zotero 的 "cheater syntax"(在extra字段中以独立行写入Label: value)向导出结果注入任意字段,并深入剖析 BBT 特有的tex./bibtex./biblatex.前缀语法、三种字段类型(text/date/name)的处理规则、原始 LaTeX 直通机制,以及 postscript 中通过extra.kv.<变量名>访问这些字段的完整方式。读完后你将能精准控制 BibTeX/BibLaTeX 与 CSL JSON/YAML 的导出内容,不再受 Zotero 内置字段限制。
Cheater syntax:在 Extra 字段中声明任意数据
所有 Zotero 条目都自带一个extra字段,它最初用于存放非结构化的补充信息。Zotero 的引文处理器支持在其中识别所谓的 "cheater syntax"——把每个字段写成独立的一行,格式为:
Label: value例如:
Original Date: 1856 Court: Supreme Court of the United StatesBBT 同样理解这套语法,并且额外添加了一种属于自己的cheater 语法(下文 "BBT 专属前缀" 一节详述)。此外,BBT 还兼容一种更古老的写法,官方文档明确标注该格式仍被支持但已废弃:
{:csl-variable: value}例如{:original-date: 1856}。两种写法效果等价,但建议新数据一律使用Label: value形式。
解析器的正则实现
BBT 对这两种格式的解析可以在 content/extra.ts 中看到。解析器维护三套正则:
const re = { old: /^{:(?<key>[^:]+)(?<assign>:)\s*(?<value>[^}]+)}$/i, // 废弃的 {:csl-var: value} 形式 new: /^(?:(?<tex>(bib(la)?)?tex\.)|(?<csl>csl\.))?(?<key>[^:=]+)\s*(?<assign>[:=])\s*(?<value>[\S\s]*)/i, // Label: value quoted: /^(?:(?<tex>(bib(la)?)?tex\.)|(?<csl>csl\.))?"(?<key>[^"]+)"\s*(?<assign>[:=])\s*(?<value>[\S\s]*)/i, // 带引号的 Label }注意new正则已经内建了对可选前缀(tex.、biblatex.、bibtex.、csl.)的识别,并用:或=两种赋值符区分不同的处理模式;quoted变体则允许把带空格的标签用引号包裹("Label": value),且解析顺序上先匹配 quoted 再匹配 new,避免引号内的冒号干扰。
三种字段类型
BBT 把 cheater 字段分为三类:
| 类型 | 说明 | 示例 |
|---|---|---|
| text | 普通文本,原样处理 | Archive: BNF archives |
| date | 日期值 | Original Date: 1856-03-04 |
| name | 人名/机构名 | Interviewer: Emily Watson |
Date(日期):BBT 会尽最大努力解析各种"疯狂"的日期写法(这也是 content/dateparser.ts 存在的意义),但如果希望结果稳定一致,官方文档强烈建议统一使用YYYY-MM-DD格式。
Name(人名):可以只写一段文本——等价于 Zotero 中的单段式名称(机构名);也可以使用||分隔符显式给出姓与名:
Interviewer: Watson || Emily在 content/extra.ts 中可以看到,name 类型值会按/\s*\|\|\s*/切分为两部分:cslCreator将其映射为 CSL 的{ family, given }结构(单段则作为literal,即机构名),zoteroCreator则映射为 Zotero 的{ lastName, firstName }结构。因此在 CSL 与 Zotero 两条导出链路中,name 字段都会被正确处理。
字段如何映射到导出变量(重要但略有绕)
写入extra的标签会被映射到两种不同的变量体系:
- Zotero 字段:如
accessDate、archiveLocation、DOI、pages; - CSL 变量:如
accessed、original-date、DOI、page。
映射到哪个体系取决于你导出到哪种格式(官方文档自己也承认这一点 "depends (sorry)"):
- 导出到 CSL(Better CSL JSON / Better CSL YAML)时:优先尝试映射到对应的 CSL 字段;如果找不到对应的 CSL 字段,则以Zotero 字段名暴露。
- 导出到 Better BibTeX / Better BibLaTeX 时:优先尝试映射到对应的 Zotero 字段;如果找不到对应的 Zotero 字段,则以CSL 变量名暴露。
这一逻辑在 content/extra.ts 中有精确实现:
if (options.kv) { const [ primary, secondary ] = mode === 'csl' ? ['csl', 'zotero'] : ['zotero', 'csl'] if (key === '_eprint') { extraFields.kv![key] = value; return false } if ((ef = Schema.labeled[primary][key]) && addMappedField(ef, value)) return false // Secondary fallback only when the key is not known in the primary mode. // Unprefixed 'type' does not fall back to CSL in Zotero mode. if ((mode === 'csl' || key !== 'type') && !Schema.labeled[primary][key] && (ef = Schema.labeled[secondary][key]) && addMappedField(ef, value)) return false }其中mode在 bibtex 导出器调用Extra.get(item.extra, 'zotero')(见 translators/bibtex/exporter.ts)时为'zotero',在 CSL 链路则传'csl'。Schema.labeled是 BBT 在 content/item-schema.ts 中构建的"标签 → 字段"双向索引(zotero与csl两张查找表),它由 Zotero 与 CSL 的 JSON schema 驱动生成。
在 postscript 中访问这些字段
这些 extra 字段在 postscript(脚本化导出) 中统一以extra.kv.<变量名>暴露。具体是哪个变量名,遵循上面的映射规则:CSL 导出用 CSL 名(失败则 Zotero 名),Bib(La)TeX 导出用 Zotero 名(失败则 CSL 名)。extra.kv只是解析结果Fields结构的一部分,完整结构见 content/extra.ts:
export type Fields = { raw: Record<string, string> // 未归一化的原始键值 kv?: Record<string, string> // 按模式映射后的 text/date 字段 csl?: Record<string, string> // 显式 csl.* 前缀字段 creator: Record<string, string[]> // name 类型字段(按 creator 角色分组) creators: Creator[] // name 类型字段的完整列表 tex?: Record<string, TeXString> // tex./bibtex./biblatex. 前缀字段 aliases?: string[] // 引文键别名 }在导出端,BibTeX/BibLaTeX 导出器确实大量消费这个结构,例如 translators/bibtex/bibtex.ts 中item.DOI || item.extraFields.kv!.DOI与item.url || item.extraFields.kv!.url,以及 translators/bibtex/biblatex.ts 中的 URL/DOI 回退逻辑——这意味着即使条目没有填写标准url/DOI字段,你也可以通过 cheater 语法补上。CSL 侧同样如此,见 translators/csl/csl.ts(extraFields.kv!.originalDate参与日期回退)。
BBT 专属前缀:tex. / bibtex. / biblatex.
除了标准的 cheater 语法,BBT 还提供一套专属的 extra 字段格式:
tex.field: value这些字段不会被映射到任何 Zotero/CSL 变量,而是被 BBT原样复制到输出中。例如在extra中写:
tex.bestfield: philosophy导出的 Bib(La)TeX 中就会出现:
bestfield = {philosophy}即tex.前缀之后的bestfield直接成为 bib(la)tex 字段名。
限定导出目标:bibtex. 与 biblatex.
你可以通过更换前缀,让字段只在某一类导出中出现:
tex.bestfield:—— 无论 BibTeX 还是 BibLaTeX 导出都会输出;bibtex.bestfield:—— 仅在BibTeX导出时输出;biblatex.bestfield:—— 仅在BibLaTeX导出时输出。
这个前缀过滤逻辑在 translators/bibtex/exporter.ts 中实现:导出器先按当前翻译器(this.translation.BetterBibLaTeX ? 'biblatex.' : 'bibtex.')选出目标前缀,再与通用前缀tex.一起,把匹配的字段"剥掉前缀"后进入输出;不匹配的字段被删除:
if (item.extraFields.tex) { // strip extra.tex fields that are not for me const prefix = this.translation.BetterBibLaTeX ? 'biblatex.' : 'bibtex.' for (const [ name, field ] of Object.entries(item.extraFields.tex).sort((a, b) => strcmp.variant(b[0], a[0]))) { for (const type of [ prefix, 'tex.' ]) { if (name.startsWith(type)) { item.extraFields.tex[name.substr(type.length)] = field break } } delete item.extraFields.tex[name] } }排序时tex.在biblatex./bibtex.之前,因此同一标签同时出现tex.与bibtex.变体时,后者优先。
:与=:文本转义 vs 原始 LaTeX 直通
前缀字段的分隔符同样有两种,语义截然不同:
:(冒号):冒号之后的内容被视为普通文本。BBT 会对其进行 LaTeX 转义(例如&会被转义),并应用大小写保护规则。=(等号):等号之后的内容被视为"raw LaTeX"——BBT不做任何转义,原样照抄进输出文件。
因此官方文档给出了一对正反示例。想要文本转义与大小写保护时,用冒号:
tex.corp: Black & Decker tex.formula= $\sum\limits_{i=1}^{n} -p(m_{i})\log_{2}(p(m_{i}))$而下面这种写法是有问题的——公式用了冒号会被转义破坏,&用了等号则变成未转义的裸 LaTeX:
tex.corp= Black & Decker tex.formula: $\sum\limits_{i=1}^{n} -p(m_{i})\log_{2}(p(m_{i}))$注意同一行里&与$...$混用时必须各自选对分隔符,这正是上面第一个示例的用意。该模式(assign === '='时mode = 'raw')同样定义在 content/extra.ts:
const texmode = (assign === '=') ? 'raw' : (tex && (tex.includes('T') || tex.match(/^[A-Z]/)) ? 'cased' : undefined)TeXString类型(content/extra.ts)就是{ value, mode?: 'raw' | 'cased', line }三要素:raw对应=,cased对应大小写保护(见下一节),line记录其在 extra 中的原始行号以便报错定位。
大小写保护:在前缀中加入大写
BBT 会对非 raw(即冒号形式)的字段应用大小写保护规则——你只需把前缀里的字母大写即可。例如:
TeX.corp: Black & Decker就会以大小写保护的方式输出corp字段,从而在标题化(title-casing)时保护词首大写。实现上,texmode判定中的tex.includes('T') || tex.match(/^[A-Z]/)正是检测前缀是否含大写字母(content/extra.ts),随后字段键会被tex = tex && tex.toLowerCase()归一化,而mode: 'cased'保留在TeXString中供编码器使用。
两个需要注意的限制
- 这些 BBT 专属字段只被 BBT 认识。官方文档明确提醒:其他导出器不认识
tex./bibtex./biblatex.前缀,某些第三方导出器甚至可能把它们当作 notes 输出——这是无法干预的。 - 它们同样会被 Zotero 的引文处理器忽略(不像无前缀的 CSL 变量那样参与 Zotero 内部引文处理)。
完整标签 / 变量对照表
官方文档在 site/layouts/shortcodes/extra-fields.md 中维护了一份完整的标签对照表(通过 Hugo shortcode{{% extra-fields %}}注入文档)。表格列出的是Zotero 字段,而不是 bibtex 字段——Zotero 字段到 bibtex 字段的翻译非常复杂,官方暂未提供简明的对应描述。下表精选了最常用的标签,完整列表(约 150 项)请直接查看上述 shortcode 文件:
| 标签(Label) | 类型 | Zotero 字段 | CSL 变量 |
|---|---|---|---|
| Original Date | date | originalDate | original-date |
| Author | name | author / creator | author |
| Container Title | text | code / publicationTitle / reporter | container-title |
| Date | date | date | issued |
| DOI | text | DOI | DOI |
| Event Place | text | eventPlace | event-place |
| Filing Date | date | filingDate | submitted |
| Genre | text | genre / programmingLanguage / type | genre |
| Issue | text | issue / priorityNumbers | issue |
| Issued | date | date | issued |
| Number | text | number | number |
| Pages | text | pages | page |
| Publication Title | text | publicationTitle | container-title |
| Publisher | text | publisher | publisher |
| References | text | history / references | references |
| Rights | text | rights | license |
| Series | text | series | collection-title |
| Source | text | libraryCatalog | source |
| Title | text | title | title |
| URL | text | url | URL |
| Volume | text | codeNumber / volume | volume |
| Year Suffix | text | — | year-suffix |
表注:① 标记为 "Juris-M only" 的字段(如attorneyAgent、assignee、court、wordsBy等法律领域字段)仅在 Juris-M 中受支持;标准 Zotero 中部分标签(如applicationNumber、archiveID / number、issueDate等)会通过斜杠/给出的多个 Zotero 字段做回退映射。
几个值得特别说明的映射细节:
- 同一 Zotero 字段可能由多个标签共享(如
publicationTitle同时由Blog Title、Book Title、Container Title、Dictionary Title、Proceedings Title、Publication Title、Session Title、Website Title等标签映射),同一标签也可能映射到多个 Zotero 字段(斜杠分隔,取第一个命中的); custom标签没有对应的 Zotero/CSL 字段(表格中留空),用于携带纯自定义信息;- 多个 CSL 变量(如
title-short、archive_location、first-reference-note-number)在 Zotero 侧没有对应字段,它们正是"导出到 Bib(La)TeX 时以 CSL 变量名暴露"的典型场景; - 反之,
archiveID、codePages、reporterVolume、seriesText等只有 Zotero 字段,没有 CSL 变量,属于"导出到 CSL 时以 Zotero 字段名暴露"的情况。
实战建议与注意事项
日期用 ISO 格式
BBT 虽然会尽力解析各种人类花式日期(March 4, 1856、1856/03等),但为了跨导出器与跨版本的一致结果,请一律使用YYYY-MM-DD。
人名用 || 分隔
需要结构化人名时使用<family> || <given>(姓在前、名在后,符合 CSL/Zotero 的惯用顺序);单个字符串则按机构/单段名处理。
raw LaTeX 的边界
只有当你确定内容已是合法 LaTeX 时才用=;包含&、%、_、$等特殊字符的普通文本务必用:,让 BBT 完成转义。
postscript 联动
所有 cheater 字段都可以在 postscript 中通过extra.kv.<变量名>读取,配合tex.add({ name, value, enc })API 可以做非常精细的二次加工;而tex.前缀字段则可以直接驱动tex.entrytype这类特殊字段——在 translators/bibtex/entry.ts 中可以看到,tex.entrytype的值会被用作导出条目的类型(例如强制输出@customa{...}之类条目),tex.referencetype作为其过渡期别名同样被支持。
免去为每个条目手工输入的自动化
把反复使用的 cheater 行写入 string 偏好(preferences) 或利用自动导出 + 模板,可以避免在每条记录里重复手工输入相同字段,这也是官方推荐的工作流方向(详见 自动导出)。
总结
Zotero 的extra字段 + cheater syntax 提供了一条"不修改任何源码即可注入任意导出字段"的通道,而 BBT 在此基础上追加了tex./bibtex./biblatex.前缀、=raw LaTeX 直通和大小写保护,让 Bib(La)TeX 用户得以完全掌控最终 .bib 文件的内容。核心实现集中在 content/extra.ts(解析与映射)、content/item-schema.ts(标签索引)与 translators/bibtex/exporter.ts(前缀过滤)三处,配合文末的完整标签对照表,你可以随时查表定位任意标签在 Zotero 与 CSL 两侧的落点。
- 科研
【免费下载链接】zotero-better-bibtex
Make Zotero effective for us LaTeX holdouts
相关推荐
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考