逐部分定义命令

逐部分定义命令

这个问题是逐部分定义命令线程。假设我们有一个带有 1 个参数的命令。我们可以生成一个重新定义为的\foo命令:如果的参数等于“aaa”,则执行“某些操作”;否则执行 \foo 之前应该执行的操作?我也想多次使用 \setfoo,所以\setfoo{aaa}{<some stuff>}\foo\foo

\setfoo{a}{part1}
\setfoo{b}{part2}
\setfoo{c}{part3}
\foo{a}  \foo{b} \foo{c}

会产生

part1 part2 part3

此外,我希望能够使用\setfooinside enumerate,然后使用\fooinside 或 outside ,因此

\begin{enumerate}
\item First item. \setfoo{1}{part 1}
\setfoo{2}{part 2}
\item Second item.
\item Some text \setfoo{3}{part 3} Some text \foo{1}
\end{enumerate}
\foo{1} \foo{2} \foo{3}

会给

1. First item.
2. Second item.
3. Some text Some text part 1
part 1 part 2 part 3

我已经尝试了 egreg 对上一个问题的解决方案,但\foo之后的所有 s\end{enumerate}都是未定义的。MWE:

\documentclass{article}

\newcommand{\setfoo}[2]{%
  \expandafter\newcommand\csname tomasz@#1\endcsname{#2}%
}


\makeatletter
\newcommand{\foo}[1]{%
  \ifcsname tomasz@#1\endcsname
     \expandafter\@firstoftwo
  \else
     \expandafter\@secondoftwo
  \fi
  {\csname tomasz@#1\endcsname}%
  {BUMMER!}%
}
\makeatother

\begin{document}
\begin{enumerate}
\item First item. \setfoo{1}{part 1}
\setfoo{2}{part 2}
\item Second item.
\item Some text \setfoo{3}{part 3} Some text \foo{1}
\end{enumerate}
\foo{1} \foo{2} \foo{3}
\end{document}

得出的结果为:

1. First item.
2. Second item.
3. Some text Some text part 1
BUMMER! BUMMER! BUMMER!

(BUMMER!是以前没有使用过\foo{<x>}的输出。)\setfoo{<x>}{<something>}

如果这可以使问题更容易,我只能使用数字作为的参数\foo,但我会很感激一般的解决方案(当的参数\foo是一些字母/数字的字符串时)。

答案1

只需将定义设为全局的:

\newcommand{\setfoo}[2]{%
  \expandafter\gdef\csname tomasz@#1\endcsname{#2}%
}

\newcommand在当前组中定义一个宏(因此显然在子组中)。当此组完成时,定义将丢失:宏定义将恢复到组启动之前的状态。在成功调用的情况下\newcommand,先前的状态必然是“未定义”或\let等于\relax,但如果\renewcommand在组内使用,则组结束时恢复的先前状态是命令在组启动之前的定义。示例:

\documentclass{article}

\begin{document}

\newcommand{\foo}{outside}

{ \renewcommand{\foo}{inside} \foo }

\foo

\end{document}

截屏

\newcommand与和朋友(\newcommand*\renewcommand\providecommand等)相反,\gdef更新以下标记的含义全局:新的定义超越了所有群体。

请注意,除了语法之外,\gdef和之间还有一些其他区别:\newcommand

  • 用 定义的命令\gdef不是\long,除非定义类似于\long\gdef\cmdname〈parameter text〉{〈replacement text〉}(在下面的例子中,您需要用 替换\gdef\long\expandafter\gdef\long宏接受包含\par标记的参数,而其他宏在使用此类参数调用时会抛出错误(著名的“失控参数”错误消息)。\long因此,不是 更具限制性,但这使在 (La)TeX 代码中查找错误变得更容易,假设人们已经决定\par标记与所定义命令的参数无关(这意味着不应将命令定义为\long;使用 LaTeX2e 内核框架,应将其定义为\newcommand*)。

  • \gdef如果被要求,会很乐意重新定义相同的命令,而\newcommand会拒绝这样做(它会抛出一个错误)。这种行为\gdef可能对你的情况来说是一个理想的特性(?)。如果不是,很容易添加一个检查,如果命令已经定义,就会出错。

经过修复的示例的完整代码\gdef

\documentclass{article}

\newcommand{\setfoo}[2]{%
  \expandafter\gdef\csname tomasz@#1\endcsname{#2}%
}


\makeatletter
\newcommand{\foo}[1]{%
  \ifcsname tomasz@#1\endcsname
     \expandafter\@firstoftwo
  \else
     \expandafter\@secondoftwo
  \fi
  {\csname tomasz@#1\endcsname}%
  {BUMMER!}%
}
\makeatother

\begin{document}
\begin{enumerate}
\item First item. \setfoo{1}{part 1}
\setfoo{2}{part 2}
\item Second item.
\item Some text \setfoo{3}{part 3} Some text \foo{1}
\end{enumerate}
\foo{1} \foo{2} \foo{3}
\end{document}

截屏

相关内容