重新定义命令 \cite 以便能够使用附加语法

重新定义命令 \cite 以便能够使用附加语法

背景

该软件包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

相关内容