宏中重复命令的次数可变

宏中重复命令的次数可变

我对 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}

相关内容