我有一个自定义环境,用于在多个环境中重新创建特定布局,格式化可变数量的文本条目enumerate
。到目前为止,我已经将多个名称相似的命令定义为可以在环境内设置的令牌,但我当前的方法需要大量\ithenelse
开关,并且可扩展性不是很好。
\newcommand{\setName}[2][]{\ifthenelse{\equal{#1}{}}{\renewcommand{\tokenName}{#2}}{\renewcommand{\tokenName}{#2 1--#1}}}
\newcommand{\setEffect}[2][]{
\ifthenelse{\equal{#1}{}}{\renewcommand{\tokenEffect}{\item[] #2}}{}
\ifthenelse{\equal{#1}{1}}{\renewcommand{\tokenEffectI}{\item #2}}{}
\ifthenelse{\equal{#1}{2}}{\renewcommand{\tokenEffectII}{\item #2}}{}
\ifthenelse{\equal{#1}{3}}{\renewcommand{\tokenEffectIII}{\item #2}}{}
\ifthenelse{\equal{#1}{X}}{\renewcommand{\tokenEffectX}{\item[each:] #2}}{}
}
\newcommand{\setRequirement}[2][]{
\ifthenelse{\equal{#1}{}}{\renewcommand{\tokenEffect}{\item[] #2}}{}
\ifthenelse{\equal{#1}{1}}{\renewcommand{\tokenRequirement}{\item #2}}{}
\ifthenelse{\equal{#1}{2}}{\renewcommand{\tokenRequirementI}{\item #2}}{}
\ifthenelse{\equal{#1}{3}}{\renewcommand{\tokenRequirementII}{\item #2}}{}
\ifthenelse{\equal{#1}{X}}{\renewcommand{\tokenRequirementIII}{\item #2}}{}
}
\newenvironment{Description}{
\newcommand{\tokenName}{}
\newcommand{\tokenEffect}{}
\newcommand{\tokenEffectI}{}
\newcommand{\tokenEffectII}{}
\newcommand{\tokenEffectIII}{}
\newcommand{\tokenEffectX}{}
\newcommand{\tokenRequirement}{}
\newcommand{\tokenRequirementI}{}
\newcommand{\tokenRequirementII}{}
\newcommand{\tokenRequirementIII}{}
}{
\section{\tokenName}
\paragraph{Effects}
\begin{enumerate}
\tokenEffect
\tokenEffectX
\tokenEffectI
\tokenEffectII
\tokenEffectIII
\end{enumerate}
\paragraph{Requirements}
\begin{enumerate}
\tokenRequirement
\tokenRequirementI
\tokenRequirementII
\tokenRequirementIII
\end{enumerate}
}
有没有更高效、更灵活的方法来替换 token 命令系统?我试过,xsavebox
但无法让它与 savebox 名称中的参数一起正常工作。
答案1
我想你想要类似的东西
\makeatletter
\newcommand{\setEffect}[2][]{%
\ifx\relax#1\relax
\def\tokenEffect{\item[] #2}%
\else\ifx X#1\relax
\def\tokenEffectX{\item[each:] #2}%
\else
\expandafter\def\csname tokenEffect\@Roman{#1}\endcsname{\item #2}%
\fi\fi}
答案2
您可以使用很多方法来定义和调用名称中也包含数字和/或空格和/或类似内容的宏 - 我在讨论中\name
详细阐述了宏\name
定义控制序列,之后留有空格。
也许这样的东西适合您的需要?:
%%----------------------------------------------------------------------
%% \name{macro} -> \macro
%% \name\string{macro} -> \string\macro
%% \name\newcommand{macro}... -> \newcommand\macro...
%% (Instead of "macro" you can also use phrases that contain digits
%% and/or spaces and/or the like.)
%%......................................................................
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\innername{#1}}%
\newcommand\innername[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\newcommand\exchange[2]{#2#1}%
%%......................................................................
\newcommand\CheckWhetherUndefined{}%
\name\global\let\CheckWhetherUndefined={@ifundefined}%
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\firstoftwo[2]{#1}%
\newcommand\secondoftwo[2]{#2}%
\newcommand\CheckWhetherNull[1]{%
\romannumeral0\expandafter\secondoftwo\string{\expandafter\secondoftwo
\expandafter{\expandafter{\string#1}\expandafter\secondoftwo\string}%
\expandafter\firstoftwo\expandafter{\expandafter\secondoftwo\string}%
\expandafter\expandafter\firstoftwo{ }{}\secondoftwo}{\expandafter
\expandafter\firstoftwo{ }{}\firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Maintaining local commands:
%%......................................................................
\newcommand\genericSet[1]{%
\name\name{\CheckWhetherUndefined{#1}{}{re}newcommand}*{#1}%
}%
\newcommand{\setName}[2][]{%
\CheckWhetherNull{#1}{\genericSet{tokenName}{#2}}{\genericSet{tokenName}{#2 1--#1}}%
\ignorespaces
}%
\newcommand{\setEffect}[2][]{\genericSet{tokenEffect#1}{#2}\ignorespaces}%
\newcommand{\setRequirement}[2][]{\genericSet{tokenRequirement#1}{#2}\ignorespaces}%
% You must never define \UnDeFInED ;-)
\newenvironment{Description}{\let\tokenName=\UnDeFInED\ignorespaces}{%
\section{\tokenName}% <- This way you will get an undefined
% control-sequence-error in case of not
% having called \setName from within the environment.
\paragraph{Effects}%
\begin{enumerate}% At least one of the following should be defined!
\CheckWhetherUndefined{tokenEffect}{}{\item[]\name{tokenEffect}}%
\CheckWhetherUndefined{tokenEffectX}{}{\item[each:]\name{tokenEffectX}}%
\CheckWhetherUndefined{tokenEffect1}{}{\item\name{tokenEffect1}}%
\CheckWhetherUndefined{tokenEffect2}{}{\item\name{tokenEffect2}}%
\CheckWhetherUndefined{tokenEffect3}{}{\item\name{tokenEffect3}}%
\end{enumerate}%
\paragraph{Requirements}%
\begin{enumerate}% At least one of the following should be defined!
\CheckWhetherUndefined{tokenRequirement}{}{\item[]\name{tokenRequirement}}%
\CheckWhetherUndefined{tokenRequirement1}{}{\item\name{tokenRequirement1}}%
\CheckWhetherUndefined{tokenRequirement2}{}{\item\name{tokenRequirement2}}%
\CheckWhetherUndefined{tokenRequirement3}{}{\item\name{tokenRequirement3}}%
\end{enumerate}%
}%
%% Usage:
% \begin{Description}
% \setName[foo]{Bar}%
% \setEffect{Token Effect}%
% \setEffect[1]{Token Effect 1}%
% \setEffect[2]{Token Effect 2}%
% \setEffect[3]{Token Effect 3}%
% \setEffect[X]{Token Effect X}%
% \setRequirement{Token Requirement}%
% \setRequirement[1]{Token Requirement 1}%
% \setRequirement[2]{Token Requirement 2}%
% \setRequirement[3]{Token Requirement 3}%
% \end{Description}
此外,仅当存在以下项目时,才可以添加\if..
-switch 来启动和结束枚举环境:
%%----------------------------------------------------------------------
%% \name{macro} -> \macro
%% \name\string{macro} -> \string\macro
%% \name\newcommand{macro}... -> \newcommand\macro...
%% (Instead of "macro" you can also use phrases that contain digits
%% and/or spaces and/or the like.)
%%......................................................................
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\innername{#1}}%
\newcommand\innername[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\newcommand\exchange[2]{#2#1}%
%%......................................................................
\newcommand\CheckWhetherUndefined{}%
\name\global\let\CheckWhetherUndefined={@ifundefined}%
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\firstoftwo[2]{#1}%
\newcommand\secondoftwo[2]{#2}%
\newcommand\CheckWhetherNull[1]{%
\romannumeral0\expandafter\secondoftwo\string{\expandafter\secondoftwo
\expandafter{\expandafter{\string#1}\expandafter\secondoftwo\string}%
\expandafter\firstoftwo\expandafter{\expandafter\secondoftwo\string}%
\expandafter\expandafter\firstoftwo{ }{}\secondoftwo}{\expandafter
\expandafter\firstoftwo{ }{}\firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Starting and ending enumerate-environment:
%%......................................................................
\newif\ifThereAlreadyIsAnItem\ThereAlreadyIsAnItemfalse
\newcommand\ProbablyStartEnumerate[1]{%
\ifThereAlreadyIsAnItem\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{}{\ThereAlreadyIsAnItemtrue#1\begin{enumerate}}%
}%
\newcommand\ProbablyStopEnumerate{%
\ifThereAlreadyIsAnItem\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\end{enumerate}\ThereAlreadyIsAnItemfalse}{}%
}%
%%----------------------------------------------------------------------
%% Maintaining local commands:
%%......................................................................
\newcommand\genericSet[1]{%
\name\name{\CheckWhetherUndefined{#1}{}{re}newcommand}*{#1}%
}%
\newcommand{\setName}[2][]{%
\CheckWhetherNull{#1}{\genericSet{tokenName}{#2}}{\genericSet{tokenName}{#2 1--#1}}%
\ignorespaces
}%
\newcommand{\setEffect}[2][]{\genericSet{tokenEffect#1}{#2}\ignorespaces}%
\newcommand{\setRequirement}[2][]{\genericSet{tokenRequirement#1}{#2}\ignorespaces}%
% You must never define \UnDeFInED ;-)
\newenvironment{Description}{%
\ThereAlreadyIsAnItemfalse
\let\tokenName=\UnDeFInED
\ignorespaces
}{%
\section{\tokenName}% <- This way you will get an undefined
% control-sequence-error in case of not
% having called \setName from within the environment.
\CheckWhetherUndefined{tokenEffect}{}{\ProbablyStartEnumerate{\paragraph{Effects}}\item[]\name{tokenEffect}}%
\CheckWhetherUndefined{tokenEffectX}{}{\ProbablyStartEnumerate{\paragraph{Effects}}\item[each:]\name{tokenEffectX}}%
\CheckWhetherUndefined{tokenEffect1}{}{\ProbablyStartEnumerate{\paragraph{Effects}}\item\name{tokenEffect1}}%
\CheckWhetherUndefined{tokenEffect2}{}{\ProbablyStartEnumerate{\paragraph{Effects}}\item\name{tokenEffect2}}%
\CheckWhetherUndefined{tokenEffect3}{}{\ProbablyStartEnumerate{\paragraph{Effects}}\item\name{tokenEffect3}}%
\ProbablyStopEnumerate
\CheckWhetherUndefined{tokenRequirement}{}{\ProbablyStartEnumerate{\paragraph{Requirements}}\item[]\name{tokenRequirement}}%
\CheckWhetherUndefined{tokenRequirement1}{}{\ProbablyStartEnumerate{\paragraph{Requirements}}\item\name{tokenRequirement1}}%
\CheckWhetherUndefined{tokenRequirement2}{}{\ProbablyStartEnumerate{\paragraph{Requirements}}\item\name{tokenRequirement2}}%
\CheckWhetherUndefined{tokenRequirement3}{}{\ProbablyStartEnumerate{\paragraph{Requirements}}\item\name{tokenRequirement3}}%
\ProbablyStopEnumerate
}%
%% Usage:
% \begin{Description}
% \setName[foo]{Bar}%
% \setEffect{Token Effect}%
% \setEffect[1]{Token Effect 1}%
% \setEffect[2]{Token Effect 2}%
% \setEffect[3]{Token Effect 3}%
% \setEffect[X]{Token Effect X}%
% \setRequirement{Token Requirement}%
% \setRequirement[1]{Token Requirement 1}%
% \setRequirement[2]{Token Requirement 2}%
% \setRequirement[3]{Token Requirement 3}%
% \end{Description}
答案3
这是可扩展的(最多可提供 100 种效果和要求)。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\prop_new:N \l_lossner_token_prop
\tl_new:N \l_lossner_token_name_tl
\NewDocumentCommand{\setName}{om}
{
\IfNoValueTF { #1 }
{
\tl_set:Nn \l_lossner_token_name_tl { #2 }
}
{
\tl_set:Nn \l_lossner_token_name_tl { #2 ~ 1--#1 }
}
}
\NewDocumentCommand{\setEffect}{om}
{
\IfNoValueTF { #1 }
{
\prop_put:Nnn \l_lossner_token_prop { effect@ } { \item[] #2 }
}
{
\str_if_eq:nnTF { #1 } { X }
{
\prop_put:Nnn \l_lossner_token_prop { effect@#1 } { \item[each:] #2 }
}
{
\prop_put:Nnn \l_lossner_token_prop { effect@#1 } { \item #2 }
}
}
}
\NewDocumentCommand{\setRequirement}{om}
{
\IfNoValueTF { #1 }
{
\prop_put:Nnn \l_lossner_token_prop { effect@ } { \item[] #2 }
}
{
\prop_put:Nnn \l_lossner_token_prop { requirement@#1 } { \item #2 }
}
}
\NewDocumentEnvironment{Description}{}
{}
{
\prop_show:N \l_lossner_token_prop
\section{\l_lossner_token_name_tl}
\paragraph{Effects}
\begin{enumerate}
\lossner_token:nn {effect}{}
\lossner_token:nn {effect}{X}
\int_step_inline:nn {100}
{
\lossner_token:nn {effect}{##1}
}
\end{enumerate}
\paragraph{Requirements}
\begin{enumerate}
\lossner_token:nn {requirement}{X}
\int_step_inline:nn {100}
{
\lossner_token:nn {requirement}{##1}
}
\end{enumerate}
}
\cs_new_protected:Nn \lossner_token:nn
{
\prop_item:Nn \l_lossner_token_prop { #1@#2 }
}
\ExplSyntaxOff
\begin{document}
\begin{Description}
\setName{abc}
\setEffect{Main}
\setEffect[1]{Wow}
\setRequirement[3]{Whatever}
\end{Description}
\begin{Description}
\setName[A]{abc}
\setEffect{Wow}
\setEffect[X]{Plus}
\setRequirement[1]{Whatever}
\setRequirement[2]{Whatever}
\setRequirement[3]{Whatever}
\setRequirement[4]{Whatever}
\setRequirement[5]{Whatever}
\setRequirement[6]{Whatever}
\setRequirement[7]{Whatever}
\setRequirement[8]{Whatever}
\setRequirement[9]{Whatever}
\end{Description}
\end{document}