问题陈述
在 biblatex v3.11 下,我定义了一个\DeclareCiteCommand
,它包括a\printfield{source}
和a\printnames
命令(参见下面的 MWE)。
该source
字段本身包含一个引用(例如source = {\cite{Rossing1990}}
),我意识到这可能是有问题的,但却是我想要实现的一个重要方面。
根据source
字段中的引用是否包含后注,将不会生成或在和\DeclareCiteCommand
之间生成分号。\printfield{source}
\printnames
- 我希望去掉分号在后一种情况下,这曾经是几个版本之前(大约 1-2 年,IIRC)biblatex 的默认行为。
- 此外,解释如果能解释一下我所观察到的现象发生的原因(参考 biblatex 文档),我将不胜感激。
最小(非)工作示例(MWE)
main.tex
文件
\documentclass{article}
\usepackage[style=authoryear-comp]{biblatex}
\addbibresource{test.bib}
\DeclareCiteCommand{\mycite}{}{%
\printfield{source} \printnames[first-last]{author}
}{}{}
\begin{document}
This citation includes a semicolon between \verb|\printfield| and \verb|\printnames| (which I am trying to get rid of):\\
\mycite{MyImg}\\
This citation doesn't (which is what I want):\\
\mycite{MyImg2}\\
\end{document}
test.bib
文件
@image{MyImg,
author = {{Addison-Wesley}},
source = {\cite{Rossing1990}},
}
@image{MyImg2,
author = {{Addison-Wesley}},
source = {\cite[45]{Rossing1990}},
}
@book{Rossing1990,
author = {Thomas D. Rossing},
date = {1990},
}
汇编
注:本 MWE 的编译需要二 biber
运行。以下序列有效:
pdflatex main
biber main
pdflatex main
biber main
pdflatex main
答案1
下面我将使用note
而不是source
(因为source
在默认数据模型中未知,所以它不会被传递给文件.bbl
- 我假设您有一个自定义.dbx
设置)。
使用\setunit{\addspace}
文字空格代替
你只需要\setunit{\addspace}
在两个\print...
命令之间添加一个就可以了
%\RequirePackage{filecontents}
\begin{filecontents}{\jobname.bib}
@image{MyImg,
author = {{Addison-Wesley}},
note = {\cite{Rossing1990}},
}
@image{MyImg2,
author = {{Addison-Wesley}},
note = {\cite[45]{Rossing1990}},
}
@book{Rossing1990,
author = {Thomas D. Rossing},
date = {1990},
}
\end{filecontents}
\documentclass{article}
\usepackage[style=authoryear-comp]{biblatex}
\addbibresource{\jobname.bib}
\DeclareCiteCommand{\mycite}{}{%
\printfield{note}%
\setunit{\addspace}%
\printnames[given-family]{author}%
}{}{}
\begin{document}
This citation includes a semicolon between \verb|\printfield| and \verb|\printnames| (which I am trying to get rid of):\\
\mycite{MyImg}\\
This citation doesn't (which is what I want):\\
\mycite{MyImg2}\\
\end{document}
为什么有\setunit
帮助?
标点符号追踪器
biblatex
对字段之间或一般命令中的标点符号采用特殊方法\print...
。不应直接插入标点符号,而应将其存储在缓冲区中,并仅在需要时打印出来。这种对文本的标点符号采用异步方法可以轻松避免不必要的双重标点符号。
您可以在§4.11.7 中阅读有关标点符号跟踪器的全部内容使用标点符号追踪器的手册biblatex
,简短版本如下:
每当需要标点符号时,标点符号不会直接插入,而是被包裹在里面\setunit
(通常使用的\newunit
相当于 ,\setunit{\newunitpunct}
默认\newunitpunct
为\addperiod\space
)。一个典型的片段是(来自volume+number+eid
在standard.bbx
)
\printfield{volume}%
\setunit*{\adddot}%
\printfield{number}%
\setunit{\addcomma\space}%
\printfield{eid}
当\setunit
遇到 时(我们\setunit*
稍后会介绍带星号的版本),biblatex
将其参数存储在标点缓冲区中,命令本身不打印任何内容。标点缓冲区可以被后续的\setunit
s 覆盖,因此\setunit{X}\setunit{Y}
只留Y
在缓冲区中。缓冲区被打印并在下一个\print...
实际打印任何内容的命令时清空。
假设在上面的例子中,条目有一个volume
和一个eid
字段,但没有number
字段。处理代码片段时volume
,将打印\setunit*
插入\adddot
标点符号缓冲区。没有number
,所以\printfield{number}
什么也不做。\setunit{\addcomma\space}
发送\addcomma\space
到缓冲区并替换其先前的值\adddot
。然后\printfield{eid}
打印eid
,但在此之前,标点符号缓冲区被打印并清空。这导致
<volume>
,<eid>
如果number
存在,我们最终会得到
<volume>
。<number>
,<eid>
带星号的版本\setunit*
检查\print...
紧接在它之前的命令是否打印了某些内容。如果是,它的行为就像,如果不是,它会丢弃它的参数并且不执行任何操作。因此,在示例中,如果有但没有 ,\setunit
则可以看到差异。假设上面的代码片段之前已插入标点符号缓冲区。使用 ,我们将得到number
volume
\printtext{Blah}\setunit{\addcomma\space}
\addcomma\space
volume
废话,
<volume>
。<number>
,<eid>
但如果没有音量并且\setunit
被使用,\adddot
则会覆盖\addcomma\space
以给出
废话
<number>
,<eid>
如果缺少\setunit*
标点符号缓冲区,则不会发生任何事情,因此我们得到volume
废话
<number>
,,<eid>
因为即使在那之后什么也没做,它\addcomma\space
仍然留在缓冲区中。\printfield{volume}
\setunit*{\adddot}
authoryear-comp
's中的标点符号\cite
引用宏authoryear-comp
可以简化为以下方案(请查看\DeclareCiteCommand{\cite}
和\newbibmacro{cite}
在authoryear-comp.cbx
)
循环代码
<Lots of `\print...` commands>
\setunit{\multicitedelim}
邮政编码
\iffieldundef{postnote}
{}
{\setunit{\postnotedelim}%
\printfield{postnote}}
对于您引用的每个条目,循环代码都会执行一次(因此\cite{sigfridsson,nussbaum}
将先执行一次循环代码 for sigfridsson
,然后再执行 for nussbaum
),邮政编码在循环结束后执行。
如果您\cite
执行没有后注的命令,即使完成后,该\cite
命令也会在标点符号缓冲区中留下一个。这是因为循环代码的最后一行是,如果是空的,则邮政编码实际上会被跳过。通常这不是问题,因为通常在标点符号跟踪器不控制其\multicitedelim
\setunit{\multicitedelim}
postnote
\cite
周围环境以及 - 通常\cite
后面没有\print...
命令 - 因此缓冲区保持设置状态,但不会被打印。下一个\cite
(或任何高级biblatex
命令)会在执行其工作之前清除缓冲区,因此在完成后将缓冲区保持非空状态没有任何坏处。但是,在您的应用程序中,and\printfield
之后有一个\cite
,它\printfield
会看到非空的标点符号缓冲区并在打印其内容之前将其插入。
如果有postnote
,那么在循环代码完成其工作并留\multicitedelim
在标点符号缓冲区中后,我们进入循环代码,采取第二个分支并遇到\setunit{\postnotedelim}
。因此,\multicitedelim
缓冲区中的 被 替换为\postnotedelim
,然后\printfield{postnote}
打印并清空标点符号缓冲区,最后打印postnote
。请注意,在这一连串事件之后,标点符号缓冲区为空。\printfield
之后的\cite
没有标点符号可插入,只是打印其文本。
请注意,这种情况是由于 的authoryear-comp
引用宏的实现细节而发生的。使用authoryear
的引用命令时不会发生这种情况。authoryear
它的循环代码不是以 结束的\setunit{\multicitedelim}
,而是\multicitedelim
使用 sepcode 参数插入\DeclareCiteCommand
。 无法做到这一点,因此必须在循环代码的末尾使用authoryear-comp
(通常)风格有问题的。\setunit{\multictedelim}
结论
标点符号和空格应始终由标点符号跟踪器处理\setunit
。切勿在命令之间直接插入空格或标点符号\print...
。
我应该补充一点,如果可能的话,\cite
应该尽量避免在.bib
条目和参考书目中使用。对于某些应用程序来说,该related
功能可能更合适,但我认为在其他情况下,解决方法并不简单,需要一些思考。
您在这里所做的实际上是嵌套引用命令。通常biblatex
会积极阻止嵌套引用命令(任何尝试过的人\cite[\cite{nussbaum}]{sigfridsson}
都知道这一点),因为它们可能会导致 的biblatex
许多跟踪功能混淆(\cite[\cite{nussbaum}]{sigfridsson}
“ibid.”应该指什么? - 即使我们认为这意味着这是合理的,也sigfridsson
很难执行,因为nussbaum
实际上是最后处理的,并且biblatex
的跟踪器必须是全局的,所以无论多少分组都无法帮助我们)。对于这种仅在受控环境中使用的高度专业化的引用命令来说,这可能不是什么大问题,但它肯定会导致正常引用命令中的混淆和意外行为。