![重新定义命令 \cite 以便能够使用附加语法](https://linux22.com/image/475338/%E9%87%8D%E6%96%B0%E5%AE%9A%E4%B9%89%E5%91%BD%E4%BB%A4%20%5Ccite%20%E4%BB%A5%E4%BE%BF%E8%83%BD%E5%A4%9F%E4%BD%BF%E7%94%A8%E9%99%84%E5%8A%A0%E8%AF%AD%E6%B3%95.png)
背景
该软件包amsrefs
重新定义了命令\cite
,以便可以使用语法“ \cite{book-name}*{optional-argument}
”来产生(基本上)与通常的“ ”相同的输出\cite[optional-argument]{book-name}
。
例如,如果这本书出现在参考书目中的第五个条目中,则命令\cite{book-name}*{pag. 42}
将输出“[5,第 42 页]”。
我想要做什么以及我的代码
我不想使用包amsrefs
,但出于测试目的,并作为学习 Tex/Latex 的练习,我试图重新定义命令,\cite
以便它能够正常使用通常的语法,但除此之外,我希望它能够使用新语法来\cite{book-name}*{optional-argument}
提供如上所示的输出,其中第一个参数是必需的,第二个参数是可选的。当然,所有这些都无需加载上述包。
简而言之,我希望\cite
能够支持这些语法:
\cite{mandatory} % Already defined by Latex
\cite[optional]{mandatory} % Already defined by Latex
\cite{mandatory}*{optional} % Defined by me
我想出了以下有效的代码(编辑:第二种语法实际上还不起作用,但目前我不在乎,我稍后会修复它):
\documentclass{article}
\usepackage[english]{babel}
% My code
\let\cites\cite % use when disabling amsrefs
\let\oldcite\cite
\makeatletter
\def\new@cite#1{\def\fappo{{#1}}\futurelet\tok@cite@custom\@newcite}
\def\@newcite{\ifx\tok@cite@custom*\let\@cchoice 2\else\let\@cchoice 1\fi\execute@cchoice}
\def\execute@cchoice{\ifx\@cchoice 1\@new@cite\else\expandafter\@new@@cite\fi}
\def\@new@cite{\expandafter\oldcite\fappo}
\def\@new@@cite*#1{\expandafter\citeinvert\fappo{#1}}
\let\newcite\new@cite
\def\citeinvert#1#2{\oldcite[#2]{#1}}
\makeatother
\let\cite\newcite
% End of my code
\begin{document}
\noindent The syntax \verb+\cite{book}+ yields \cite{greenwade93}.\\
% The syntax \verb+\cite[opt]{book}+ yields \cite[page 42]{greenwade93}.\\ (DOES NOT WORK YET)
The syntax \verb+\cite{book}*{opt}+ yields \cite{greenwade93}*{page 42}.
\bibliographystyle{plain}
\bibliography{sample}
\end{document}
有什么建议吗?
我没有确切的问题,但我想知道是否有办法简化代码,或者是否有不同的更简单的方法。
我遇到的主要困难是,每当我使用一个\ifx
来决定使用哪个版本的命令(取决于它应该吃多少个参数)时,所选版本的命令总是想要吃掉\else
或\fi
宏内的\expandafter
(顺便说一句,这就是我使用第一个的原因)。这是我设法编写的最短的工作代码,但我挣扎了很多,我怀疑我忽略了一些让事情更顺利进行的技巧。
我刚刚开始了解代币的工作原理,我读过本指南由 Overleaf 提供,以及关于的一些其他事情\futurelet
等等,但我的知识非常薄弱和稀疏。
答案1
我不会重新定义,\cite
但如果你愿意,可以直接用\NewDocumentCommand
(见texdoc usrguide
)声明所需的参数规范
\documentclass{article}
\NewCommandCopy\oldcite\cite
\ExplSyntaxOn
\RenewDocumentCommand\cite{O{}mE{*}{{}}}{%
\tl_if_empty:nTF{#1#3}{\oldcite}{\oldcite[#1#3]}{#2}}
\ExplSyntaxOff
\begin{document}
\cite{aaa}
\cite[bbb]{aaa}
\cite{aaa}*{ddd}
\cite[fff]{aaa}*{hhh}
\begin{thebibliography}{1}
\bibitem{aaa} Some item
\end{thebibliography}
\end{document}
答案2
我担心大卫的回答并不正确。
您需要检查是否传递了可选参数,无论是作为“经典”参数还是在之后*
。如果没有,那么您需要\oldcite
在不使用可选参数的情况下调用,否则您总是会在引用键后得到“逗号和空格”。
\documentclass{article}
\ExplSyntaxOn
\NewCommandCopy{\oldcite}{\cite}
\RenewDocumentCommand\cite{ome{*}}
{
\lorenzo_cite:nnn { #1 } { #2 } { #3 }
}
\cs_new_protected:Nn \lorenzo_cite:nnn
{
\bool_lazy_and:nnTF { \tl_if_novalue_p:n { #1 } } { \tl_if_novalue_p:n { #3 } }
{
\oldcite{#2}
}
{
\oldcite[\tl_if_novalue:nF {#1}{#1} \tl_if_novalue:nF {#3}{#3}]{#2}
}
}
\ExplSyntaxOff
\begin{document}
\cite{aaa}
\cite[bbb]{aaa}
\cite{aaa}*{ddd}
\cite[fff]{aaa}*{hhh}
\begin{thebibliography}{1}
\bibitem{aaa} Some item
\end{thebibliography}
\end{document}
如果使用两个可选参数,则修改为在控制台和日志文件中打印警告。
\documentclass{article}
\ExplSyntaxOn
\NewCommandCopy{\oldcite}{\cite}
\RenewDocumentCommand\cite{ome{*}}
{
\lorenzo_cite:nnn { #1 } { #2 } { #3 }
}
\cs_new_protected:Nn \lorenzo_cite:nnn
{
\bool_lazy_and:nnTF { \tl_if_novalue_p:n { #1 } } { \tl_if_novalue_p:n { #3 } }
{
\oldcite{#2}
}
{
\bool_lazy_and:nnT { !\tl_if_novalue_p:n { #1 } } { !\tl_if_novalue_p:n { #3 } }
{
\iow_term:e
{
WARNING:~double~optional~argument~in~
\token_to_str:N \cite\c_space_tl
on~line~\msg_line_context:
}
}
\oldcite[\tl_if_novalue:nF {#1}{#1} \tl_if_novalue:nF {#3}{#3}]{#2}
}
}
\ExplSyntaxOff
\begin{document}
\cite{aaa}
\cite[bbb]{aaa}
\cite{aaa}*{ddd}
\cite[fff]{aaa}*{hhh}
\begin{thebibliography}{1}
\bibitem{aaa} Some item
\end{thebibliography}
\end{document}
您将获得与之前相同的输出,但终端将显示
WARNING: double optional argument in \cite on line on line 42