在 LaTeX 中,有没有办法定义一个宏(或其他东西)来替换每个实例
\cite{a_literal_string}
和
\ref{appendix:a_different_literal_string}
无需触及\cite
没有参数的实例a_literal_string
?我想对几种不同的可能替代品进行同样的操作。
这里的想法是,我将一些模块化文档纳入一个更大的项目,并希望将其中一些用作附录。我不想只是查找/替换,因为当子文档未在更大的项目中使用时,它们需要能够相互引用。
答案1
expl3
以下是使用和的实现xparse
:
\begin{filecontents*}{\jobname.bib}
@article{cite:a,
author={A. Uthor},
title={Title a},
journal={J. A},
year={2014},
}
@article{cite:b,
author={B. Athor},
title={Title b},
journal={J. B},
year={2014},
}
@article{cite:c,
author={C. Ethor},
title={Title c},
journal={J. C},
year={2014},
}
\end{filecontents*}
\documentclass{article}
\usepackage{xparse,letltxmacro}
\LetLtxMacro{\latexcite}{\cite}
\ExplSyntaxOn
\RenewDocumentCommand{\cite}{om}
{
\IfNoValueTF{#1}
{ \daniel_cite_or_ref:n { #2 } }
{ \latexcite[#1]{#2} }
}
\NewDocumentCommand{\addsubstitution}{mm}
{
\tl_gput_right:Nn \g_daniel_changes_tl { {#1}{\ref{#2}} }
}
\tl_new:N \g_daniel_changes_tl
\cs_new_protected:Npn \daniel_cite_or_ref:n #1
{
\str_case:nVTF { #1 } \g_daniel_changes_tl
{
% \nocite{#1} %%%% <---- uncomment this line if you want \nocite
}
{
\latexcite{#1}
}
}
\cs_generate_variant:Nn \str_case:nnTF { nV }
\ExplSyntaxOff
\addsubstitution{cite:a}{ref:a}
\addsubstitution{cite:b}{ref:b}
\begin{document}
\section{Something}\label{sec:some}
Here we do the citations: \cite{cite:a}, \cite{cite:b},
\cite{cite:c} and \cite[p.~42]{cite:c}
\appendix
\section{First appendix}\label{ref:a}
Text
\section{Second appendix}\label{ref:b}
Text
\bibliographystyle{plain}
\bibliography{\jobname}
\end{document}
您应该在\cite
命令中只使用一个项目;考虑替换的多个引用是可能的,但它需要对最终格式做出决定。
使用\addsubstitution
命令添加您想要执行的替换:第一个参数是引用键,第二个参数是标签。
在参考文献中仅插入实际引用的项目;如果您还想添加替换的项目,只需取消\nocite
上面宏的注释即可。
实施注意事项
该expl3
函数\str_case:nnTF
有四个参数:
- 要检查的字符串;
- 一组对
{<string>}{<action>}
; - 如果找到匹配项该怎么办?
- 如果没有找到匹配项该怎么办。
对于变体\str_case:nVTF
,第二个参数是包含对集的标记列表变量。
如果给出了可选参数,则新\cite
命令将使用原始命令;否则,它将控制权传递给检查参数是否符合存储在中的一组对的命令;此变量由任意数量的命令填充。\cite
\daniel_cite_or_ref:n
\g_daniel_changes_tl
\addsubstitution
添加其他功能虽然不简单,但很容易,例如在参数中接受多个键,\cite
并决定当键需要替换时该做什么。
答案2
如果您愿意使用 LuaLaTeX,那么您可以使用 Lua 的强大string.gsub
函数来实现您的目标。在下面的示例中,Lua 端代码存储在名为 的文件中string_replacements.lua
。(除了最简单的情况外,通常最简单的方法是将 Lua 代码存储在单独的文件中并使用指令调用它\directlua{ require("string_replacements.lua")}
。)该函数replace_string
可以执行多个字符串替换。Is 被分配给process_input_buffer
回调,它会完成其工作前LaTeX 进行任何处理;输入文件的内容不会被修改。
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luatexbase}
\directlua{require("string_replacements.lua")}
\begin{document}
\section{Hello}
Here's a cross-reference to Appendix \cite{a_literal_string}.
And here's a cross-reference to abcdefuvwxyz.
\appendix
\section{Good-bye} \label{appendix:a_different_literal_string}
\begin{equation} \label{eq:pyth}
a^2+b^2=c^2
\end{equation}
\end{document}
其内容string_replacements.lua
为:
-- string_replacements.lua
local function replace_string ( line )
line = string.gsub ( line,
"\\cite{a_literal_string}" ,
"\\ref{appendix:a_different_literal_string}" )
line = string.gsub ( line,
"abcdefuvwxyz",
"equation~(\\ref{eq:pyth})" )
return line
end
luatexbase.add_to_callback( "process_input_buffer",
replace_string, "replace_string" )
答案3
也许你需要这样的东西:
\def\speclabel#1#2{\expandafter\def\csname slab:#1\endcsname{#2}}
\let\citeOri=\cite
\def\cite#1{\expandafter\ifx\csname slab:#1\endcsname\relax\citeOri{#1}%
\else \expandafter\expandafter\expandafter\ref
\expandafter\expandafter\expandafter{\csname slab:#1\endcsname}\fi
}
\speclabel {a_literal_string} {a_different_literal_string}
\speclabel {another_literal_strig} {another_different_litral_string}
Now \cite{normal} behaves normal but \cite{a_literal_string} expands
to \ref{a_different_literal_string}.
您必须通过\speclabel
宏声明转换,然后才能使用正常的\cite
。