我有一个关于操作 bst 文件以删除中间名首字母后的句点的问题。假设以下 .bib 文件条目:
@BOOK{author1999book,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {First M. Last},
}
我一直在对apa.bst
文件进行各种修改,以创建一个与特定期刊相匹配的 bst 文件。他们要求的一件事是中间名首字母后面不能有句号。因此,他们的参考书目部分样式如下:
姓氏,名字 M (1999)内容丰富且精美的书. 大学城,圣路易斯县:大学城出版社。
我已经修改了apa.bst
文件以解决其他格式问题(年份周围的括号、标题的大写)。剩下的就是中间名首字母后的句号问题。
现在,我只需在 .bib 文件条目中删除中间名首字母后面的句点即可。不过,我想做的是在 *.bst 文件中找到一种方法来做到这一点。可以吗?我之所以问这个问题,是因为如果是,几种 bst 样式实际上会包含该句点不是在 *.bib 文件中。我想要做的是让 bst 文件从中间首字母中删除句点,如果它是在 *.bib 文件中。我不知道这是否可行,如果可行,我该怎么做。
答案1
格式化文件内的名称列表的函数bst
名为format.names
。例如,对于文件apa.bst
,此函数具有以下代码:
FUNCTION {format.names}
{ 's :=
#1 'nameptr :=
s num.names$ 'numnames :=
numnames 'namesleft :=
{ namesleft #0 > }
{ s nameptr "{vv~}{ll}{, jj}{, f.}" format.name$ 't := % last name first
nameptr #1 >
[... etc ...]
}
有关文件和此功能中使用的语法的详细信息bst
,请参阅文档驯服野兽(第 35 页)。
在这种情况下,我们必须修改的行是包含该字符串的行:
"{vv~}{ll}{, jj}{, f.}"
此字符串指定每个作者姓名所需的格式。vv
表示“von”部分(如果存在)ll
是完整的姓氏,jj
表示“junior”部分(如果存在),最后ff
是完整的名字,而f
表示名字的首字母。逗号和点是文字,并添加到输出中。
删除后面的点f
即可得到您想要的结果,或者几乎是您想要的结果:
请注意,由于我们使用了f
而不是ff
,所以名字和中间名都是缩写。但是使用 时,ff
我们将两者都展开。显然,BibTeX 没有“中间名”的概念,所有不是姓氏的都被视为名字。
如果您需要“完全展开”的第一个名字,但中间名缩写且不带点,那么这超出了我的 bibtex 能力。我甚至不知道这是否可行。
答案2
我向同事展示了我最初的答案(如下),他发现了一个病态案例。我应该指出,我们的特定应用首先是针对缩写的和中间名(与 OP 询问的不完全相同,但是是一种很常见的需求)。
他对我说:“你知道,有一个简单的方法可以解决这个问题。”编辑解析名称的 .bst 文件(它看起来像nameptr "{ff~}{vv~}{ll}{, jj}"
),并将名字字段(带有f
)更改为{f{}~}
(或者{f{}}
如果它是作者字段中出现的最后一项)。
那有多容易?! 它对我们的应用程序来说非常有效。虽然它不完全是 OP 的查询,但我认为它非常有用,我想将其列在网站上,以便其他需要定制作者字段的人使用。
更新:我后来得知,这个技巧是由 Oren Patashnik 在他的文档“BibTeXing”的最后一段中提供的,可以在以下网址找到:http://bibtexml.sourceforge.net/btxdoc.pdf。
更改 plain.bst 中的那一行会产生以下 MWE(与我的原始答案相同):
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{mybib.bib}
@BOOK{author1999book,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {First M. Last},
}
@BOOK{test2,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {Last, First M.},
}
@BOOK{test3,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {Last, F. M.},
}
\end{filecontents}
\bibliographystyle{plain}
%%BibTeX Dot Removal Macro
\let\svdot. % CAN SAVE THE DOT IF NEEDED SOMEWHERE IN AUTHOR LIST
\catcode`.=\active
\def\NoBibDots#1{\let.\relax#1\catcode`.=12}
% THE FOLLOWING LINE WOULD BE USEFUL FOR "Last FM, ..." FORMATS
%\def\NoBibDots#1{\def~{ }\let.\ignorespaces#1\catcode`.=12}
\catcode`.=12
\begin{document}
Citing\cite{author1999book,test2,test3}
\bibliography{mybib}
\end{document}
产生此输出
原始答案:
我对这个问题思考了一段时间(自去年 7 月以来),试图解析作者以删除点,但遇到了一些小问题和怪癖。但后来我想到了一个不同的想法,即.
激活删除点。它实际上会从作者列表中删除每个点(可以通过\svdot{}
在 bib 条目中使用来撤销)。
在本 MWE 中,我使用了 plain.bst,但已验证该方法适用于其他配置(可能需要进行一些调整)。我提供了注释代码,用于使用方法的 bst 文件LAST FM
(请参阅apalike
本文末尾的示例)。要准备 bst 文件,请添加此宏:
FUNCTION {no.bib.dots}
{ duplicate$ empty$
{ pop$ "" }
{ "\catcode`.=\active\NoBibDots{" swap$ * "}\catcode`.=12" * }
if$
}
并修改此标准:
FUNCTION {format.authors}
{ author empty$
{ "" }
% { author format.names }% THIS WAS THE ORIGINAL LINE REPLACED BELOW
{ author format.names no.bib.dots "." * }
if$
}
注意
{ author format.names no.bib.dots "." * }
可以替换为
{ author format.names no.bib.dots "~" * }
如果你想要一个尾随空格而不是句点,或者简单地使用
{ author format.names no.bib.dots }
既不包含空格也不包含句号。然后,在您的文档、样式或类中,定义\NoBibDots
如下:
%%BibTeX Dot Removal Macro
\let\svdot. % CAN SAVE THE DOT IF NEEDED SOMEWHERE IN AUTHOR LIST
\catcode`.=\active
\def\NoBibDots#1{\let.\relax#1\catcode`.=12}
% THE FOLLOWING LINE WOULD BE USEFUL FOR "Last FM, ..." FORMATS
%\def\NoBibDots#1{\def~{ }\let.\ignorespaces#1\catcode`.=12}
\catcode`.=12
以下是完整的 MWE 和相关结果:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{mybib.bib}
@BOOK{author1999book,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {First M. Last},
}
@BOOK{test2,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {Last, First M.},
}
@BOOK{test3,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {Last, F. M.},
}
\end{filecontents}
\bibliographystyle{plain}
%%BibTeX Dot Removal Macro
\let\svdot. % CAN SAVE THE DOT IF NEEDED SOMEWHERE IN AUTHOR LIST
\catcode`.=\active
\def\NoBibDots#1{\let.\relax#1\catcode`.=12}
% THE FOLLOWING LINE WOULD BE USEFUL FOR "Last FM, ..." FORMATS
%\def\NoBibDots#1{\def~{ }\let.\ignorespaces#1\catcode`.=12}
\catcode`.=12
\begin{document}
Citing\cite{author1999book,test2,test3}
\bibliography{mybib}
\end{document}
为了演示其他 bst 样式的灵活性,我对 apalike.bst 进行了与上述 plain.bst 相同的更改。 apalike
具有“Last, FM”格式,我想将其表示为“Last, FM。”。以下 MWE 中,我重新定义\NoBibDots
为在删除点后吸收空格,给出了相关结果:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{junk.bib}
@ARTICLE{bake67,
TITLE = "Prediction and scaling of reflected impulse from
strong blast waves",
AUTHOR = "Baker, W. E.",
JOURNAL = "International Journal of Mechanical Sciences",
VOLUME = "9",
NUMBER = "1",
PAGES = "45--51",
YEAR = "1967" }
@ARTICLE{Acme72,
TITLE = "Prediction and scaling of reflected impulse from
strong blast waves",
AUTHOR = "Acme, Wesley E.",
JOURNAL = "International Journal of Mechanical Sciences",
VOLUME = "9",
NUMBER = "1",
PAGES = "45--51",
YEAR = "1972" }
@ARTICLE{cake71,
TITLE = "Prediction and scaling of reflected impulse from
strong blast waves",
AUTHOR = "Cake, Wesley Excaliber",
JOURNAL = "International Journal of Mechanical Sciences",
VOLUME = "9",
NUMBER = "1",
PAGES = "45--51",
YEAR = "1971" }
@ARTICLE{Delta71,
TITLE = "Prediction and scaling of reflected impulse from
strong blast waves",
AUTHOR = "Delta, W. Excaliber",
JOURNAL = "International Journal of Mechanical Sciences",
VOLUME = "9",
NUMBER = "1",
PAGES = "45--51",
YEAR = "1971" }
\end{filecontents}
%%BibTeX Dot Removal Macro
\let\svdot. % CAN SAVE THE DOT IF NEEDED SOMEWHERE IN AUTHOR LIST
\catcode`.=\active
%\def\NoBibDots#1{\let.\relax#1\catcode`.=12}
% THE FOLLOWING LINE WOULD BE USEFUL FOR "Last FM, ..." FORMATS
\def\NoBibDots#1{\def~{ }\let.\ignorespaces#1\catcode`.=12}
\catcode`.=12
\begin{document}
cite \cite{bake67, Acme72, cake71, Delta71}
\bibliographystyle{apalike}
\bibliography{junk}
\end{document}
答案3
在深入研究bst
语法之后,我终于能够编写解决方案。我的“简单破解”结果并不那么简单,所以我认为它值得一个新的详细答案。
我的想法是使用format.name$
具有格式的函数"{ff}"
仅提取名字(在您的示例中为“First Medium”),然后再次使用format.name$
此结果,并使用字符串"{ff}{ l}"
根据需要获取“First M”。
但后来我尝试涵盖这种简单黑客攻击会失败的其他可能性,例如作者没有中间名,甚至没有名字(仅提供姓氏)。由于检测和处理此类情况的代码开始变得过于复杂,我编写了一个特定函数来完成所有这些工作,然后从主格式化作者函数中调用该函数。
调用新函数format.trick
,并期望堆栈顶部有一个包含单个作者姓名的字符串(例如“First Medium Last”,也接受符号“Last, First Medium”。此函数在堆栈顶部留下“规范化”名称,即“Last, First M”。它可以正确处理没有媒介名称或没有名字的作者。这是此函数的大量注释代码:
STRINGS {ss tt fm}
FUNCTION {format.trick}
{
'ss := %% Make a copy of the name in s
%% Extract the First (and possible Medium) names
%% and store it in variable fm
ss #1 "{ff}" format.name$ 'fm :=
%% Note that now fm could contain:
%% * An empty string ("") if the author has no first name (only Last name was provided)
%% * A single word (like "First") if the author has no medium name
%% * A sequence of words (like "First Medium")
%% For the last case we want to abbreviate "Medium", without dot
%% Test if we are in the first case
fm empty$ {
% If empty (no first name), use the standard formatting
ss #1 "{vv~}{ll}{, jj}{, ff}" format.name$
}{ % Otherwise, attempt the trick
%% Now the trick. Interpret "First Medium"
%% as if "Medium" were a last name, and abbreviate it
fm #1 "{ff }{l}" format.name$ 'tt := %% And store the result in tt
%% Consider the particular case in which no Medium name is present
%% In this case, "First" will be interpreted as a last name, and
%% thus abbreviated. This can be detected because the resulting
%% string has length 1
tt text.length$ #1 > { %% If there was a medium name
tt %% Store the abbreviated version
}{ %% Else store the original version of the name
fm
} if$
%% After the above, the top of the stack will contain
%% either "First" unabbreviated (if the author has not middle name)
%% or "First M", as required
'tt := %% Copy that value to tt
%% Now complete the standard formatting of the author, omitting
%% the first name part, which is stored in tt
ss #1 "{vv~}{ll}{, jj}" format.name$
%% And concatenate to it the value of tt
", " *
tt *
}if$ %% If the trick has to be done
}
您可以在函数bst
之前的任何位置插入该代码format.names
,然后修改format.names
函数,更改以下行:
{ s nameptr "{vv~}{ll}{, jj}{, ff}" format.name$ 't :=
到
{ s nameptr "{vv~}{ll}{, jj}{, f}" format.name$
% Postprocess result
format.trick 't :=
我尝试了新的包含复杂作者列表的.bst
方法:bib
@BOOK{author1999book,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {
Last, First Middle
and Lastonly
and Last2, First2 M.
and Last3, First3 M
and Last4, Firstonly
}
}
它按预期工作:
理解基于堆栈的 bst 语言很有趣。:-)
更新
OP 使用的bst
风格稍微复杂一些,其中第一位作者的格式与其余作者不同。这使得我的上述技巧无法直接使用。OP 为我提供了完整的内容bst
,我能够找到需要修改哪些行以适应上述技巧。
函数format.authors
和format.rem.authors
(分别生成第一作者和其余作者的格式)必须像这样修改(虽然只需要更改两行,但我更喜欢粘贴完整的函数):
FUNCTION {format.rem.names}
{ 's :=
'f :=
#2 'nameptr :=
s num.names$ 'numnames :=
numnames #1 - 'namesleft :=
{ namesleft #0 > }
{ s nameptr f format.name$ % <-----
format.trick % <-----
#1 f format.name$ 't := % <-----
nameptr #1 >
{ namesleft #1 >
{ "; " * t * }
{ t "others" =
{ " et~al." * }
{ " \& " * t * }
if$
}
if$
}
't
if$
nameptr #1 + 'nameptr :=
namesleft #1 - 'namesleft :=
}
while$
}
FUNCTION {format.authors}
{ author empty$
{ "" }
{ author #1 "{vv~}{ll}{, jj}{, ff}" format.name$
format.trick %% <----
#1 "{vv~}{ll}{, jj}{, ff}" format.name$ %% <----
"{ff }{vv~}{ll}{, jj}" author format.rem.names
}
if$
}
该函数的代码format.trick
与我在上面的原始答案中给出的代码相同。
经过这些更改后,参考书目条目如下所示:
请注意,第一作者是“姓,名”,而其余作者是“名,姓”,并且在所有情况下,中间名都缩写而不带点。我猜这是所需的输出。