natbib
并hyperref
默认创建两个指向文档参考部分|章节中的 bibentry 的链接:
\begin{filecontents}{\jobname.bib}
@book{author08,
title = {{A Title}},
publisher = {Alpha},
year = {2008},
author = {Author, A},
address = {London}
}
@book{buthor90,
title = {{B Title}},
publisher = {Bravo},
year = {1990},
editor = {Buthor, B},
address = {New York}
}
\end{filecontents}
\documentclass{article}
\usepackage{natbib}
\usepackage{hyperref}
\hypersetup{colorlinks,citecolor=red}
\begin{document}
\noindent
citet: \citet{author08}, \citet[see][p. 20]{author08} \\
citep: \citep{author08}, \citep[see][p. 20]{author08}
\bibliographystyle{plainnat}
\bibliography{\jobname}
\end{document}
为了避免出现两个参考书目链接(一个链接指向[作者],一个链接指向[年份]),我采用了奥黛丽的解决方案回答一个老问题并将其添加到我的序言中。
\usepackage{etoolbox}
\makeatletter
\pretocmd{\NAT@citex}{%
\let\NAT@hyper@\NAT@hyper@citex
\def\NAT@postnote{#2}%
\setcounter{NAT@total@cites}{0}%
\setcounter{NAT@count@cites}{0}%
\forcsvlist{\stepcounter{NAT@total@cites}\@gobble}{#3}}{}{}
\newcounter{NAT@total@cites}
\newcounter{NAT@count@cites}
\def\NAT@postnote{}
% include postnote and \citet closing bracket in hyperlink
\def\NAT@hyper@citex#1{%
\stepcounter{NAT@count@cites}%
\hyper@natlinkstart{\@citeb\@extra@b@citeb}#1%
\ifnumequal{\value{NAT@count@cites}}{\value{NAT@total@cites}}
{\ifNAT@swa\else\if*\NAT@postnote*\else%
\NAT@cmt\NAT@postnote\global\def\NAT@postnote{}\fi\fi}{}%
\ifNAT@swa\else\if\relax\NAT@date\relax
\else\NAT@@close\global\let\NAT@nm\@empty\fi\fi% avoid compact citations
\hyper@natlinkend}
\renewcommand\hyper@natlinkbreak[2]{#1}
% avoid extraneous postnotes, closing brackets
\patchcmd{\NAT@citex}
{\ifNAT@swa\else\if*#2*\else\NAT@cmt#2\fi
\if\relax\NAT@date\relax\else\NAT@@close\fi\fi}{}{}{}
\patchcmd{\NAT@citex}
{\if\relax\NAT@date\relax\NAT@def@citea\else\NAT@def@citea@close\fi}
{\if\relax\NAT@date\relax\NAT@def@citea\else\NAT@def@citea@space\fi}{}{}
\makeatother
这几乎让我达到了我想要的目标,但仍有两个问题需要解决:
- 虽然
\citet
链接中包含前注和后注,但\citep
不包括。如何才能\citep
更改为包含后注? - 有没有办法将未修改的第一个例子中用黑色排版的括号和逗号在修改后的第二个例子中也变成黑色,而无需将它们从链接中删除?
答案1
链接后记\citep
已在上一个问题。要设置黑色文本中的标点符号,您可以修补 natbib 的内部标点符号命令。这些修补程序可以推迟到文档的开头,以说明标点符号命令可以\bibpunct
在文档前言的任何位置重新定义(例如,)。
\documentclass{article}
\usepackage{natbib}
\usepackage[colorlinks]{hyperref}
\usepackage{etoolbox}
\makeatletter
% count citations
\pretocmd{\NAT@citex}{%
\let\NAT@hyper@\NAT@hyper@citex
\def\NAT@postnote{#2}%
\setcounter{NAT@total@cites}{0}%
\setcounter{NAT@count@cites}{0}%
\forcsvlist{\stepcounter{NAT@total@cites}\@gobble}{#3}}{}{}
\newcounter{NAT@total@cites}
\newcounter{NAT@count@cites}
\def\NAT@postnote{}
% include postnote and \citet closing bracket in hyperlink
\def\NAT@hyper@citex#1{%
\stepcounter{NAT@count@cites}%
\hyper@natlinkstart{\@citeb\@extra@b@citeb}#1%
\ifnumequal{\value{NAT@count@cites}}{\value{NAT@total@cites}}
{\if*\NAT@postnote*\else\NAT@cmt\NAT@postnote\global\def\NAT@postnote{}\fi}{}%
\ifNAT@swa\else\if\relax\NAT@date\relax
\else\NAT@@close\global\let\NAT@nm\@empty\fi\fi% avoid compact citations
\hyper@natlinkend}
\renewcommand\hyper@natlinkbreak[2]{#1}
% avoid extraneous postnotes, closing brackets
\patchcmd{\NAT@citex}
{\ifNAT@swa\else\if*#2*\else\NAT@cmt#2\fi
\if\relax\NAT@date\relax\else\NAT@@close\fi\fi}{}{}{}
\patchcmd{\NAT@citex}
{\if\relax\NAT@date\relax\NAT@def@citea\else\NAT@def@citea@close\fi}
{\if\relax\NAT@date\relax\NAT@def@citea\else\NAT@def@citea@space\fi}{}{}
\patchcmd{\NAT@cite}{\if*#3*}{\if*\NAT@postnote*}{}{}
% all punctuation black
\AtBeginDocument{%
\preto\NAT@sep{\textcolor{black}\bgroup}%
\appto\NAT@sep{\egroup}%
\preto\NAT@aysep{\textcolor{black}\bgroup}%
\appto\NAT@aysep{\egroup}%
\preto\NAT@yrsep{\textcolor{black}\bgroup}%
\appto\NAT@yrsep{\egroup}%
\preto\NAT@cmt{\textcolor{black}\bgroup}%
\appto\NAT@cmt{\egroup}%
\preto\NAT@open{\textcolor{black}\bgroup}%
\appto\NAT@open{\egroup}%
\preto\NAT@close{\textcolor{black}\bgroup}%
\appto\NAT@close{\egroup}}
\makeatother
\begin{filecontents}{\jobname.bib}
@book{companion,
author = {Goossens, Michel and Mittelbach, Frank and Samarin, Alexander},
title = {The LaTeX Companion},
edition = {1},
publisher = {Addison-Wesley},
location = {Reading, Mass.},
year = {1994}}
@book{adams:life,
title = {Life, the Universe and Everything},
author = {Adams, Douglas},
series = {The Hitchhiker's Guide to the Galaxy},
publisher = {Pan Macmillan},
year = {1980}}
@book{adams:rest,
title = {The Restaurant at the End of the Universe},
author = {Douglas Adams},
series = {The Hitchhiker's Guide to the Galaxy},
publisher = {Pan Macmillan},
year = {1980}}
\end{filecontents}
\newcommand{\cmd}[1]{\textbackslash\texttt{#1}}
\begin{document}
\noindent
\cmd{citet}: \citet[e.g.][pp.~1--10]{companion} \\
\cmd{citet}: \citet[pp.~1--10]{companion,adams:rest,adams:life} \\
\cmd{cite}: \cite[e.g.][p.~100]{adams:life}; \cite{adams:rest} \\
\cmd{citep}: \citep[e.g.][p.~1--10]{adams:rest,adams:life} \\
\cmd{citetext}; \cmd{citealp}:
\citetext{see \citealp[pp.~10]{adams:rest}; or even better \citealp{adams:life}} \\
\cmd{citeauthor}: \citeauthor{adams:life}; \citeauthor{companion} \\
\cmd{citeyear}: \citeyear{adams:life}; \citeyear{adams:rest} \\
\bibliographystyle{plainnat}
\bibliography{\jobname}
\end{document}
答案2
摆弄我的问题,并使用egreg 对之前帖子的解决方案,我找到了一个适合我的具体情况的解决方案:
我定义了新的命令\mycitet
,并\mycitep
以这种方式
\usepackage{twoopt}
\usepackage{ifthen}
\newcommand\black[1]{\textcolor[rgb]{0,0,0}{#1}}
\newcommandtwoopt{\mycitet}[3][aa][bb]{%
\ifthenelse{\equal{#1}{aa}} % if nargin == 1
{\hyperlink{cite.#3}{\citeauthor{#3} \black{(}\citeyear{#3}\black{)}}} % \citet{key}
{\ifthenelse{\equal{#2}{bb}} % elseif nargin == 2
{\hyperlink{cite.#3}{\citeauthor{#3} \black{(}\citeyear{#3}\black{,}~#1\black{)}}} % \citet[pg]{key}
{\ifthenelse{\equal{#1}{}} % elseif #1 = []
{\hyperlink{cite.#3}{\citeauthor{#3} \black{(}\citeyear{#3}\black{,}~#2\black{)}}} % \citet[][pg]{key}
{\ifthenelse{\equal{#2}{}} % elseif #2 == []
{\hyperlink{cite.#3}{\citeauthor{#3} \black{(#1~}\citeyear{#3}\black{)}}} % \citet[eg][]{key}
% % else
{\hyperlink{cite.#3}{\citeauthor{#3} \black{(#1~}\citeyear{#3}\black{,}~#2\black{)}}} % \citet[eg][pg]{key}}
}
}
}
}
\makeatletter
\newcommand{\multicite}[1]{% taken from egreg, see link
\@tempswafalse
\@for\next:=#1\do
{\if@tempswa;~\else\@tempswatrue\fi
\hyperlink{cite.\next}{\citeauthor{\next}\black{,~}\citeyear{\next}}%
}%
}
\makeatother
\newcommandtwoopt{\mycitep}[3][aa][bb]{%
\ifthenelse{\equal{#1}{aa}} % if nargin == 1
{(\multicite{#3})} % \citep{key(s)}
{\ifthenelse{\equal{#2}{bb}} % elseif nargin == 2
{(\hyperlink{cite.#3}{\citeauthor{#3}\black{,~}\citeyear{#3}\black{,~}#1})} % \citep[pg]{key}
{\ifthenelse{\equal{#1}{}} % elseif #1 = []
{(\hyperlink{cite.#3}{\citeauthor{#3}\black{,~}\citeyear{#3}\black{,~}#2})} % \citep[][pg]{key}
{\ifthenelse{\equal{#2}{}} % elseif #2 == []
{(#1~\multicite{#3})} % \citep[eg][]{key(s)}
% % else
{(#1~\hyperlink{cite.#3}{\citeauthor{#3}\black{,~}\citeyear{#3}\black{,~}#2})} % \citep[eg][pg]{key}}
}
}
}
}
为了演示目的,我还将文档更改为
\begin{document}
\begin{tabular}{lll}
& Audrey & me, myself and I \\
\hline\hline
citet\{key\} & \citet{author08} & \mycitet{author08} \\
citet[pg]\{key\} & \citet[pg.7]{author08} & \mycitet[pg.7]{author08} \\
citet[ ][pg]\{key\} & \citet[][pg.7]{author08} & \mycitet[][pg.7]{author08} \\
citet[eg][ ]\{key\} & \citet[e.g.][]{author08} & \mycitet[e.g.][]{author08} \\
citet[eg][pg]\{key\} & \citet[e.g.][pg.7]{author08} & \mycitet[e.g.][pg.7]{author08} \\
\hline
citep\{key\} & \citep{author08} & \mycitep{author08} \\
citep[pg]\{key\} & \citep[pg.7]{author08} & \mycitep[pg.7]{author08} \\
citep[ ][pg]\{key\} & \citep[][pg.7]{author08} & \mycitep[][pg.7]{author08} \\
citep[eg][ ]\{key\} & \citep[e.g.][]{author08} & \mycitep[e.g.][]{author08} \\
citep[eg][pg]\{key\} & \citep[e.g.][pg.7]{author08} & \mycitep[e.g.][pg.7]{author08} \\
\hline
citep\{key1,key2\} & \citep{author08,buthor90} & \mycitep{author08,buthor90} \\
citep[eg][ ]\{key1,key2\} & \citep[e.g.][]{author08,buthor90} & \mycitep[e.g.][]{author08,buthor90} \\
\end{tabular}
\bibliographystyle{plainnat}
\bibliography{\jobname}
\end{document}
得到我想要的东西:
然而,虽然这可以完美地展示我想要的东西,但我更希望对这个具体问题有一个通用的解决方案,因为
- 这种方法不会自动将括号适配到 \bibliographystyle
\let\citep\mycitep
如果我和它可能会弄乱其他命令\let\citet\mycitet
PS:有人可以解释一下 egreg 的代码片段如何知道“,”是我的分隔符吗?