我对 Latex 还很陌生,过去几天我一直在努力创建一个宏来插入带有标签的方案。我为我的方案使用 .eps 文件,其中包含一个临时标记,然后由 chemstyle 包将其替换为数字。命令是,\schemeref
包括临时标记和标签(名为 cmpd...)。如果只有一个项目需要标记,我的宏就可以工作:
\documentclass{article}
\usepackage{chemstyle}
\begin{document}
\newcommand\insertscheme[5]{%
\begin{scheme}
\schemeref[#1]{cmpd:#2}
\includegraphics{#3}
\caption{#4}
\label{scheme:#5}
\end{scheme}}
\insertscheme
{TMP1}{benzene}
{benzene.eps}{Structure of \compound{cmpd:benzene}.}{benzene}
\end{document}
但是,我也有包含多个结构的方案,通常在 2 到 7 个之间。如果没有宏,我也可以标记所有结构,如下例所示:
\begin{scheme}
\schemeref[TMP1]{cmpd:benzene}
\schemeref[TMP2]{cmpd:Brbenzene}
\includegraphics{benzene-Brbenzene.eps}
\caption{Structure of \compound{cmpd:benzene} and \compound{cmpd:Brbenzene}.}
\label{scheme:benzene-Brbenzene}
\end{scheme}
我现在的问题是:我需要如何改变宏以便它可以用于内部具有可变数字结构的方案?
我在 Overleaf 上使用 LaTeX 编译器。
答案1
如果您的所有调用\insertscheme
都是模式
\insertscheme{⟨IDENTIFIER A⟩}%
{⟨IDENTIFIER B⟩}%
{⟨IDENTIFIER B⟩.eps}%
{Structure of \compound{cmpd:⟨IDENTIFIER B⟩}.}%
{⟨IDENTIFIER B⟩}%
,那么你可以定义
\newcommand\insertscheme[2]{%
\begin{scheme}%
\schemeref[{#1}]{cmpd:#2}%
\includegraphics{#2.eps}%
\caption{Structure of \compound{cmpd:#2}.}%
\label{scheme:#2}%
\end{scheme}%
}
并且做。\insertscheme{⟨IDENTIFIER A⟩}{⟨IDENTIFIER B⟩}%
然后,您可以定义一个宏\insertschemes
来处理以逗号分隔的双参数元组列表,其工作原理如下:
\insertschemes{%
{TMP1}{benzene},
...
{TMP2}{Brbenzene},
}%
\insertschemes
下面示例中的宏如果被调用为
\insertschemes{%
{TMP1}{benzene},
{TMP2}{Brbenzene},
{TMP3}{Fbenzene},
}%
,创建代币
\begin{scheme}%
\schemeref[{TMP1}]{cmpd:benzene}%
\schemeref[{TMP2}]{cmpd:Brbenzene}%
\schemeref[{TMP3}]{cmpd:Fbenzene}%
\includegraphics{benzene-Brbenzene-Fbenzene.eps}%
\caption{%
Structure of \compound{cmpd:benzene} %
and \compound{cmpd:Brbenzene} %
and \compound{cmpd:Fbenzene}%
}%
\label{scheme:benzene-Brbenzene-Fbenzene}%
\end{scheme}%
为你。
\documentclass{article}
\usepackage{chemstyle}
\usepackage{xparse}
\ExplSyntaxOn
\clist_new:N \l__my_insertschemes_clist
\tl_new:N \l__my_insertschemes_schemerefs_tl
\tl_new:N \l__my_insertschemes_compounds_tl
\tl_new:N \l__my_insertschemes_names_tl
\bool_new:N \__bool_my_insertschemes_names_first_item
\cs_new_protected:Nn \__my_insertschemes_set_tls:nn {
\bool_if:NTF \__bool_my_insertschemes_names_first_item {
\bool_set_false:N \__bool_my_insertschemes_names_first_item
}{
\tl_put_right:Nn \l__my_insertschemes_compounds_tl {~and~}
\tl_put_right:Nn \l__my_insertschemes_names_tl {-}
}
\tl_put_right:Nn \l__my_insertschemes_compounds_tl {\compound{cmpd:#2}}
\tl_put_right:Nn \l__my_insertschemes_names_tl {#2}
\tl_put_right:Nn \l__my_insertschemes_schemerefs_tl {
\schemeref[{#1}]{cmpd:#2}
}
}
\cs_new_protected:Nn \__my_insertschemes_use_tls:nnnn{
% If you want to see what this does, uncomment the following two comments:
%\def\tempa{
\begin{#1}
#2
\includegraphics{#3.eps}
\caption{Structure~of~#4}
\label{scheme:#3}
\end{#1}
%}\show\tempa
}
\cs_generate_variant:Nn \__my_insertschemes_use_tls:nnnn {nVVV}
\NewDocumentCommand \insertschemes {m} {
\group_begin:
\clist_clear:N \l__my_insertschemes_clist
\tl_clear:N \l__my_insertschemes_schemerefs_tl
\tl_clear:N \l__my_insertschemes_compounds_tl
\tl_clear:N \l__my_insertschemes_names_tl
\clist_set:Nn \l__my_insertschemes_clist {#1}
\bool_set_true:N \__bool_my_insertschemes_names_first_item
\clist_map_inline:Nn \l__my_insertschemes_clist {
\__my_insertschemes_set_tls:nn ##1
}
\__my_insertschemes_use_tls:nVVV {scheme}
{\l__my_insertschemes_schemerefs_tl}
{\l__my_insertschemes_names_tl}
{\l__my_insertschemes_compounds_tl}
\group_end:
}
\ExplSyntaxOff
\begin{document}
\insertschemes{%
{TMP1}{benzene},
{TMP2}{Brbenzene},
{TMP3}{Fbenzene},
}%
\end{document}
如果每个参数元组需要处理两个以上的参数,那么您需要做的就是重新定义\__my_insertschemes_set_tls:nn
以处理两个以上的参数/标识符。
编辑1:
这是我第一次尝试使用 expl3/LaTeX3。
说实话,我喜欢wipet 的方法好多了:
他的宏很短,而且都是可扩展的。
他的方法非常节省资源,因为在任何循环中都不会进行临时分配,例如定义临时辅助宏等。
有了这个,\doscheme
您就不需要输入那么多花括号了。;-)
编辑2:
现在擦拭已经开始行动了,他的代码的一个变体,在\doscheme
第二个参数为空的特殊情况下\compounds
,不会\compound
在第一次迭代中创建-command:
\documentclass{article}
\usepackage{chemstyle}
\def\doscheme[#1]#2{%
\begin{scheme}%
\schemerefs #1--;#2--%
\includegraphics{#2.eps}%
\caption{Structure of \compounds{}#2--.}%
\label{scheme:#2}%
\end{scheme}%
}
\def\schemerefs #1-#2;#3-{%
\ifx^#1^\else\schemeref[{#1}]{cmpd:#3}\afterfi{\schemerefs#2;}\fi
}
\def\compounds #1#2-{%
\ifx^#2^\else#1\compound{cmpd:#2}\afterfi{\compounds{ and }}\fi
}
\def\afterfi#1#2\fi{\fi#1}
\begin{document}
Tests:
\doscheme[TMP1]{benzene}
\doscheme[TMP1-TMP2]{benzene-Brbenzene}
\doscheme[TMP1-TMP2-TMP3]{benzene-Brbenzene-Rkbenzene}
\end{document}
如果您不希望自动创建图像文件的名称、标题文本和交叉引用标签的名称,但希望将它们作为参数传递,则以下代码定义了其中的变\insertschemes
体
\insertschemes{%
{TMP1}{benzene},
{TMP2}{Brbenzene},
{TMP3}{Fbenzene},
}{NameOfImageFile}{text of caption}{CrossReferencingLabel}%
交付代币
\begin{scheme}%
\schemeref[{TMP1}]{cmpd:benzene}%
\schemeref[{TMP2}]{cmpd:Brbenzene}%
\schemeref[{TMP3}]{cmpd:Fbenzene}%
\includegraphics{NameOfImageFile.eps}%
\caption{text of caption}%
\label{scheme:CrossReferencingLabel}%
\end{scheme}%
\schemeref
,即仅自动创建命令序列:
\documentclass{article}
\usepackage{chemstyle}
\usepackage{xparse}
\ExplSyntaxOn
\clist_new:N \l__my_insertschemes_clist
\tl_new:N \l__my_insertschemes_schemerefs_tl
\cs_new_protected:Nn \__my_insertschemes_set_tls:nn {
\tl_put_right:Nn \l__my_insertschemes_schemerefs_tl {
\schemeref[{#1}]{cmpd:#2}
}
}
\cs_new_protected:Nn \__my_insertschemes_use_tls:nnnnn {
% If you want to see what this does, uncomment the following two comments:
%\def\tempa{
\begin{#1}
#2
\includegraphics{#4.eps}
\caption{#3}
\label{scheme:#5}
\end{#1}
%}\show\tempa
}
\cs_generate_variant:Nn \__my_insertschemes_use_tls:nnnnn {nVnnn}
\NewDocumentCommand \insertschemes {mmmm} {
\group_begin:
\clist_clear:N \l__my_insertschemes_clist
\tl_clear:N \l__my_insertschemes_schemerefs_tl
\clist_set:Nn \l__my_insertschemes_clist {#1}
\clist_map_inline:Nn \l__my_insertschemes_clist {
\__my_insertschemes_set_tls:nn ##1
}
\__my_insertschemes_use_tls:nVnnn {scheme}
{\l__my_insertschemes_schemerefs_tl}
{#3}
{#2}
{#4}
\group_end:
}
\ExplSyntaxOff
\begin{document}
\insertschemes{%
{TMP1}{benzene},
{TMP2}{Brbenzene},
{TMP3}{Fbenzene},
}{NameOfImageFile}{text of caption}{CrossReferencingLabel}%
\end{document}
参数元组中的可选参数\schemeref
是可选的语法也可以在没有 expl3 的情况下实现 - 这里循环在方案环境内执行:
\documentclass{article}
\usepackage{chemstyle}
\makeatletter
\begingroup
% \Removespaces removes one leading and one trailing space from its argument if present.
% Be aware that this implementation also removes a leading implicit space token like
% \@sptoken but does not remove a trailing implicit space token.
\def\Removespaces#1{%
\endgroup
\newcommand\Removespaces[1]{%
% Let's have \romannmeral create a negative number from an alphabetic constant.
% The negative number will not be printed by \romannumeral but things get expanded
% while scanning for the <optional space> that is probably trailing the alphabetic
% constant and that is also removed if present. (It will be present if the argument
% of \Removespaces has a leading space.)
\romannumeral-`\A\EnsureForbiddenBeforeTrailSpace\noexpand##1\UD@Forbidden#1\UD@Forbidden
}
}\Removespaces{ }%
\@ifdefinable\EnsureForbiddenBeforeTrailSpace{%
\long\def\EnsureForbiddenBeforeTrailSpace#1 \UD@Forbidden{%
\RemoveTrailingForbiddens#1\UD@Forbidden
}%
}%
\@ifdefinable\RemoveTrailingForbiddens{%
\long\def\RemoveTrailingForbiddens#1\UD@Forbidden#2{#1}%
}%
\@ifdefinable\gobbledot{\def\gobbledot.{}}%
\@ifdefinable\schemerefloop{%
\long\def\schemerefloop#1,{%
\if$\detokenize\expandafter{\@secondoftwo#1{}}$%
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\schemerefloop.}{%
\expandafter\expandafter
\expandafter\expandafter
\expandafter\expandafter
\expandafter\doschemeref
\expandafter\Removespaces
\expandafter{\gobbledot#1}%
}%
}%
}%
\newcommand\doschemeref{%
\@ifnextchar[\doschemeref@opt\doschemeref@noopt
}%
\newcommand\doschemeref@opt[2][]{%
\schemeref[{#1}]{cmpd:#2}\schemerefloop.%
}%
\newcommand\doschemeref@noopt[1]{%
\ifx\schemerefloop#1\expandafter\@gobble\else\expandafter\@firstofone\fi
{\schemeref{cmpd:#1}\schemerefloop.}%
}%
\@ifdefinable\insertschemes{%
\DeclareRobustCommand\insertschemes[4]{%
\begin{scheme}%
\schemerefloop.#1,{\schemerefloop},%
\includegraphics{#2.eps}%
\caption{#3}%
\label{#4}%
\end{scheme}%
}%
}%
\makeatother
\begin{document}
\insertschemes{%
[TMP1]{benzene},
{Brbenzene},
[TMP3]{Fbenzene},
}{NameOfImageFile}{text of caption}{CrossReferencingLabel}%
\end{document}
答案2
您可以为创建多个键值选项\insertscheme
:
\documentclass{article}
\usepackage{chemstyle,graphicx,xkeyval}
\makeatletter
\define@cmdkey{fam}{scheme}[\empty@key]{}
\define@cmdkey{fam}{schemeopt}[]{}
\define@cmdkey{fam}{compoundAref}[]{}
\define@cmdkey{fam}{compoundAlabel}[\empty@key]{}
\define@cmdkey{fam}{compoundBref}[]{}
\define@cmdkey{fam}{compoundBlabel}[\empty@key]{}
% Add additional compound keys here...
\define@cmdkey{fam}{caption}[\empty@key]{}
\define@cmdkey{fam}{label}[\empty@key]{}
\newcommand{\insertscheme}[1]{{%
\setkeys{fam}{%
schemeopt=,
%compoundAref=,
compoundAlabel=,
compoundBref=,
compoundBlabel=,
% Add additional compound key defaults here...
label=,
#1
}%
\begin{scheme}
\ifx\cmdKV@fam@compoundAlabel\empty@key\else
\begingroup\edef\x{\endgroup\noexpand\schemeref[\cmdKV@fam@compoundAref]{cmpd:\cmdKV@fam@compoundAlabel}}\x
\fi
\ifx\cmdKV@fam@compoundBlabel\empty@key\else
\begingroup\edef\x{\endgroup\noexpand\schemeref[\cmdKV@fam@compoundBref]{cmpd:\cmdKV@fam@compoundBlabel}}\x
\fi
% Add additional compounds here...
\ifx\cmdKV@fam@scheme\empty@key\else
\begingroup\edef\x{\endgroup\noexpand\includegraphics[\cmdKV@fam@schemeopt]{\cmdKV@fam@scheme}}\x
\fi
\ifx\cmdKV@fam@caption\empty@key\else
\caption{\cmdKV@fam@caption}%
\fi
\ifx\cmdKV@fam@label\empty@key\else
\expandafter\label\expandafter{scheme:\cmdKV@fam@label}%
\fi
\end{scheme}
}}
\makeatother
\begin{document}
\insertscheme{%
scheme=example-image,
schemeopt={width=5em},
compoundAref=TMP1,
compoundAlabel=benzene,
compoundBref=TMP2,
compoundBlabel=Brbenzene,
caption={Structure of \compound{cmpd:benzene} and \compound{cmpd:Brbenzene}.}
}
\end{document}
您可以添加额外的复合键compoundCref
,,compoundClabel
...并在其中添加额外的设置\insertscheme
以满足您的需要。
答案3
我建议使用\doscheme
宏语法
\doscheme[TMPA-TMPB-etc.]{nameA-nameB-etc.}
其作用是:
- 打开环境
scheme
\schemeref[TMPA]{cmpd:nameA}\schemeref[TMPB]{cmpd:nameB}
循环执行等等。- 插入
nameA-nameB-etc.eps
图片。 - 插入标题
Structure of \compound{cmpd:nameA} and \cmpound{cmpd:nameB} and
...(循环) - 插入标签
scheme:nameA-nameB-etc
。 - 关闭环境
scheme
。
例子:
\documentclass{article}
\usepackage{chemstyle}
\def\doscheme[#1]#2{%
\begin{scheme}
\schemerefs #1--;#2--;%
\includegraphics{#2.eps}
\caption{Structure of \compounds #2--.}
\label{scheme:#2}
\end{scheme}
}
\def\schemerefs #1-#2;#3-#4;{%
\ifx^#1^\else \schemeref[#1]{cmpd:#3}\afterfi{\schemerefs#2;#4;}\fi
}
\def\compounds #1-{\compound{cmpd:#1}\compoundsA}
\def\compoundsA #1-{%
\ifx^#1^\else\space and \compound{cmpd:#1}\expandafter\compoundsA\fi
}
\def\afterfi#1#2\fi{\fi#1}
\begin{document}
Tests:
\doscheme[TMP1]{benzene}
\doscheme[TMP1-TMP2]{benzene-Brbenzene}
\doscheme[TMP1-TMP2-TMP3]{benzene-Brbenzene-Rkbenzene}
\end{document}
答案4
如果您想采用这种方式,您可以添加\protect
以使其工作。(我不建议使用具有如此多参数的宏,几乎不可能回忆起它们的用法,特别是如果您有多个宏。)
\documentclass{article}
\usepackage{chemstyle}
\begin{document}
\newcommand\insertscheme[5]{%
\begin{scheme}
\schemeref[#1]{cmpd:#2}
\includegraphics{#3}
\caption{#4}
\label{scheme:#5}
\end{scheme}}
\insertscheme
{TMP1}{benzene}
{benzene.eps}{Structure of \protect\compound{cmpd:benzene}.}{benzene}
\end{document}