foreach 中的 Newcommand:多个参数和 minipage 环境

foreach 中的 Newcommand:多个参数和 minipage 环境

我正在尝试在循环中定义多个复杂的newcommands foreach。这听起来很简单,但为什么这么难?

天真的尝试:

\documentclass{report}

\usepackage{tikz}

\foreach \i in {first,second,third}{
    \expandafter\newcommand\csname\i\endcsname[3]{ % IYO: how readable is this "naive try"?

        command name: \i

        \begin{minipage}[\textwidth]
        first argument: ##1

        second argument: ##2

        third argument: ##3
        \end{minipage}
    }
}

\begin{document}

\first{1}{2}{3}\\

\second{a}{b}{c}\\

\third{Is}{\LaTeX}{cool?}\\

\end{document} 

这吐了:

! Undefined control sequence.
l.22     \first
               {1}{2}{3}\\

好的,\newcommand没有在 的范围之外定义命令\foreach。添加\global任何地方有帮助吗?如果有,它无法弄清楚将其放在哪里。(基本的 LaTeX 经验法则:没有什么是直观的)

我必须承认这是头痛。幸运的是,那里有互联网,所以感谢你们和 Stack 网站。途中的主要陷阱:

  • \global似乎只适用于\def所以使用\gdef而不是\newcommand
  • \i不会扩展为<the loop counter>但为\iota,因此使用\edef因此使用\xdef
  • \def系列处理参数规范的方式不同,因此使用##1##2##3而不是[3](这看起来更美观,可读性更强,易于维护。我 ##1##2##3。有一天我需要 5 个参数而不是 3 个,我所要做的就是.. 别介意。)
  • ..我甚至不敢要求支持可选参数。毕竟,这才 2016 年。

最后,这确实可以编译:

\documentclass{report}

\usepackage{tikz}

\foreach \i in {first,second,third}{
    \expandafter\xdef\csname\i\endcsname##1##2##3{ % yum

        command name: \i

        % \begin{minipage}[\textwidth]
        first argument: ##1

        second argument: ##2

        third argument: ##3
        % \end{minipage}
    }
}

\begin{document}

\first{1}{2}{3}\\

\second{a}{b}{c}\\

\third{What}{a}{pain!}\\

\end{document}

..这让我明白:

在此处输入图片描述

但是,如果我取消注释与环境有关的行,它就不再起作用minipage

! Use of \@iminipage doesn't match its definition.
\IfFileExists #1#2#3->\openin \@inputcheck #1 
                                              \ifeof \@inputcheck \ifx \inpu...
l.18     }

(顺便说一句,这真是一个令人印象深刻的线索。谢谢你,编译器。也许我应该让我的思想更加坚定,否则你和我将和谐地融合在一起,再也不会是两个。)

简而言之,考虑以下情况:

  • 为什么minipage不工作?我该如何让它工作?
  • 有没有什么办法可以让我拥有并\first支持可选参数?\second\third
  • 我是不是在重新发明轮子?调查方法不对?有没有更好的方法?

就是这样。感谢您的耐心。

非常感谢您的到来。 :)

答案1

在我看来,你使用了错误的工具:

\documentclass{report}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\xforeach}{s m +m}
 {
  \IfBooleanTF{#1}
   {
    \clist_map_inline:on { #2 } { #3 }
   }
   {
    \clist_map_inline:nn { #2 } { #3 }
   }
 }
\cs_generate_variant:Nn \clist_map_inline:nn { o }
\ExplSyntaxOff

\xforeach{first,second,third}
 {
  \expandafter\newcommand\csname#1\endcsname[3]{%is this "naive try"?
    \par\bigskip
    command name: #1
    \par\nopagebreak\medskip
    \begin{minipage}{.5\textwidth}
      first argument: ##1

      second argument: ##2

      third argument: ##3
    \end{minipage}
  }
 }

\setlength{\parindent}{0pt} % just for the example

\begin{document}

\first{1}{2}{3}

\second{a}{b}{c}

\third{Is}{\LaTeX}{cool?}

\end{document} 

如您所见,当前正在处理的项目用#1而不是表示,\i并且##1可以像往常一样用作内部参数。

在此处输入图片描述

如果需要使用宏扩展到列表,请使用\xforeach*

 \newcommand{\mylist}{first,second,third}

 \xforeach*{\mylist}{<whatever>}

答案2

您需要防止\begin扩展\xdef,并且小页面宽度不需要,{}除了[]您几乎已经到达那里之外,我还修复了一些白色空间问题。

\documentclass{report}

\usepackage{tikz}

\foreach \i in {first,second,third}{%
    \expandafter\xdef\csname\i\endcsname##1##2##3{% yum

        command name: \i

        \noindent\noexpand\begin{minipage}{\textwidth}
        first argument: ##1

        second argument: ##2

        third argument: ##3
        \noexpand\end{minipage}%
    }%
}

\begin{document}


\first{1}{2}{3}

\second{a}{b}{c}

\third{What}{a}{pain!}

\end{document}

也许我会使用不同的循环宏,而不会引入不需要的组:

\documentclass{report}

% \usepackage{tikz}

\newcommand\dodefs[1]{%
    \expandafter\newcommand\csname#1\endcsname[3][?]{% yum

        command name: #1

        \noindent\begin{minipage}{\textwidth}
        first argument: ##1

        second argument: ##2

        third argument: ##3
        \end{minipage}%
  }%
}

\makeatletter

\@for\i:=first,second,third\do{%

\expandafter\dodefs\expandafter{\i}

}
\makeatother

\begin{document}

%\show\first
\first[1]{2}{3}

\first{2}{3}

\second[a]{b}{c}

\third[What]{a}{pain!}

\end{document}

相关内容