xpatch
提供了一系列专门用于支持修补biblatex
bibmacros、参考书目驱动程序和字段/名称/列表格式的修补命令(据我所知,不是引用命令)。
在 TeX.SX 中,我有时会在 biblatex 相关答案中看到这些可能性的使用。但更常见的是(我的印象),我们发现了对各个 bibmacros、驱动程序和格式的完整重新定义。
在某些情况下,是否有明确的理由使用其中一种方法或另一种方法?一般来说,这两种方法的优缺点是什么?提出这个问题的另一种方式是什么时候最好使用一种方法还是另一种方法?
虽然我想从一般角度考虑这个问题,但我特别感兴趣的是修补的与完全重新定义的 bibmacros/drivers/formats 对 biblatex 中的更改/更新的恢复能力。
注意:这个问题可能源于我对修补代码的一般不熟悉。如果这个问题太模糊而无法“照原样”回答,我将避免提出这个问题。但我认为这个问题可能很有用。我真的很想了解更有经验的用户在选择修补还是重新定义 biblatex 时所采用的标准。
答案1
这是一个有趣的问题。我认为这个问题也可以应用于更一般的场景,但由于我主要关注的是biblatex
书目领域,所以我将坚持讨论。
通常,重新定义的性质是,只有 才\xpatchbibmacro
相关,\xapptobibmacro
而\xpretobibmacro
,它们的语法稍微简单一些,通常不适用。\xpatchbibmacro
的语法是。该命令将中\xpatchbibmacro{<bibmacro>}{<search>}{<replace>}{<success>}{<failure>}
的第一个实例替换为。<search>
<bibmacro>
<replace>
一般来说,我更喜欢直接重新定义 bibmacros,而不是通过xpatch
。
这种方法的优点是
xpatch
无需加载,从而减少开销。(编辑事实上,xpatch
基于 LaTeX3 宏并加载expl3
。开销可能微不足道,但确实存在。xpatch
需求expl3
不再相关,因为expl3
现在是 LaTeX 内核的一部分。)我还假设修补比简单地重新定义宏更昂贵,但我无法在这里给你确切的数字 - 差异可能可以忽略不计。语法稍微简单一些:
\renewbibmacro{foo}{<new definition>}
vs\xpatchbibmacro{foo}{<search>}{<replace>}{<success>}{<failure>}
。- 通常,更改仅涉及几行,因此很容易复制原始
\newbibmacro{foo}
定义,放入并修改宏代码。将要更改的代码复制到参数中,将修改后的代码添加到并添加代码(通常只是空组,但不要忘记它们)re
可能会有点麻烦。\xpatchbibmacro{foo}
<search>
<replace>
<success>
<failure>
- 对于需要进行大量更改的短宏,
\renewbibmacro
其实际上可能更短。
- 通常,更改仅涉及几行,因此很容易复制原始
\renewbibmacro
对读者来说可能更有启发,因为他们可以看到整个相关的宏\renewbibmacro*{issue+date}{% \printtext[parens]{% \printfield{issue}% \setunit*{\addcomma\space}%<- change here \usebibmacro{date}}% \newunit}
更清楚地显示了新代码的作用
\xpatchbibmacro{issue+date} {\setunit*{\addspace}} {\setunit*{\addcomma\space}} {}{}
读者不必查阅原始定义即可了解宏的新行为。不过,他们必须查阅原始定义才能准确比较更改的内容。
这也意味着更容易扩展或采用变化。
缺点是
灵活性较低。
xpatch
您不必知道要修补的宏的确切定义。只有代码<search>
是相关的。因此,xpatch
如果修改应该独立于使用的样式,则在某种程度上是有用的。代码长度。为了改变一个标点符号而复制数十行代码可能被视为过分。
这就是为什么我有时会使用xpatch
。人们真的很喜欢短代码。在一定程度上biblatex
, 倾向于划分并使用许多嵌套的短 bibmacros,这允许在许多情况下进行微小的更改而无需太多代码。但有些 bibmacros 很长,bibdrivers 也是如此。
以我的回答为例如何自定义 \textcite 命令?。 本来\renewbibmacro
大约有 50 行,而\xpatchbibmacro
只需要 5 行。所有这一切都是为了将一个更改\printnames{labelname}
为\printnames[first-last]{labelname}
。
尤其是当需要直接更改 bibdrivers 时,我更喜欢xpatch
使用\DeclareBibliographyDriver
。您的平均标准 bibdriver 长度为 30 到 40 行。如果需要更改多个驱动程序,则小的更改可能会积累数百行代码。示例可以在Biblatex/Biber:将系列、卷数和编号放在末尾和如何将字段注释移至参考文献末尾。
这两种方法在更改 bibmacros 和驱动程序时都存在问题。大多数普通用户想要更改的 bibmacros 和驱动程序多年来一直非常稳定。这并不是说不会偶尔更改更频繁更改的宏,但这种情况通常很少见。
的明显优势在于xpatch
,如果相关<search>
代码及其上下文没有改变,那么即使在更新宏后,修补也很可能继续正确执行。但是,如果代码<search>
被修改,修补将失败。如果在宏中添加了类似于的新代码<search>
,则将修补宏的错误部分。所有这些都成立,前提是命令和宏使用<replace>
没有发生重大变化。
另一方面,用 重新定义的宏\renewbibmacro
将始终应用相同的更改。它们当然容易受到应用于其<new definition>
参数中使用的命令和宏的所有更改的影响。使用 ,\renewbibmacro
您更有可能错过新功能或错误修复,因为您覆盖了整个定义,而不仅仅是部分定义。但只要 中使用的宏和命令<new definition>
没有重命名或更改为执行与其先前行为相反的操作,您的重新定义将继续执行其编写的操作。
拿https://github.com/plk/biblatex/commit/04c939eed70ed2264a2753a811a2364e7f70d4ef作为第一个例子。如果您根据更改前的代码重新定义了editor
bibmacro ,则除非您修改,否则\renewcommand
将无法正常使用。但是,您的代码将继续像以前一样工作。如果您曾经更改与该更改无关的宏部分,则一切将继续按预期工作,并且您可以使用新的。如果您修补了与更改相关的某些内容,即显式的,则您的修补程序将失败。editortypedelim
renewcommand
\xpatchbibmacro
editor
editortypedelim
\setunit{\addcomma\space}
第二个例子是https://github.com/plk/biblatex/commit/189d90db9dbe94dd08f47261e79df09e2a37c66a和https://github.com/plk/biblatex/commit/320f114d493ca7fa310c559c3a48b5912282fa22。如果您想要更改已重命名的宏之一,例如\usebibmacro{date+extrayear}
,这两种方法都不会产生良好的结果。如果您更改了调用已重命名的宏之一的宏,例如bbx:editor
来自的bibmacro authoryear.bbx
,则又有两种情况。如果代码不涉及,则该xpatch
方法完全没有问题。如果涉及,则会失败。另一方面,如果您重新定义和引用,如果不是在提交中采取向后兼容性措施,事情就会出错。<search>
\usebibmacro{date+extrayear}
<search>
\usebibmacro{date+extrayear}
xpatchbibmacro
bbx:editor
<new definition>
\usebibmacro{date+extrayear}
CTAN 上的样式比我预期的要多xpatch
。
biblatex-abnt
\xpretobibmacro{textcite}
仅用于更改 的分隔符和名称格式\textcite
。biblatex-archaeology
用来\xpatchbibdriver
避免重复整个驱动程序定义。biblatex-morenames
可以与多种风格一起使用。biblatex-opcit-booktitle
补丁引用了几种引用样式的宏。biblatex-oxref
\xpatchcmd
使用、\xpatchbibmacro
和的多个实例\xpatchbibdriver
。biblatex-realauthor
修补几个 bibmacros。biblatex-source-division
有一个\xapptobibmacro
修补几个引用命令。
其中一些用途是避免一遍又一遍地从同一个包中复制整个定义。在这些情况下,xpatch
这是一种避免代码重复的简短而优雅的方法。这相当安全,因为修补的宏通常在同一个包中定义,并且不太可能在补丁作者没有注意到的情况下发生变化。其他用途涉及修补 bibdrivers。由于驱动程序很长,因此复制整个驱动程序只是为了修补一行很麻烦。一些包过去xpatch
独立于底层样式工作。