The following throws an "Undefined control sequence" error:
\edef\testa{\edef\testb{foobar}\testb}
当涉及到扩展 \testb 时。这个问题在“TEX by Topic”12.6.2 中也提到过。但没有给出解决方案。
EDIT2,这是一个最小的不起作用的例子:
\documentclass{article}
\newenvironment{definition}[1]{\def\currentdef{#1}}{}
\makeatletter
\newcommand\contains[2]{%
\edef\listarg{#1}%
\xdef\needle{#2}%
\expandafter\contains@sub\listarg,\relax\noexpand\@eolst%
}
\def\contains@sub#1,#2\@eolst{%
\edef\match{#1}%
\ifx\needle\match%
true
\else
\ifx\relax#2\relax\else
\contains@sub#2\@eolst%
\fi
\fi}
\newcommand\cond[1]{%
\edef\test{\contains{\currentdef}{#1}}%
\ifx\relax\test\relax\def\ommitthis\relax\fi%
\@ifundefined{ommitthis}{#1}{}%
}
\makeatother
\def\test{test2}
\begin{document}
\begin{definition}{test2,test3}
\cond{test3}
\cond{\test}
\cond{test1}
\end{definition}
\end{document}
\cond
应检查给定的参数是否在周围定义中列出。因此必须省略 test2 和 test3,只应打印 test1。
答案1
您只需要循环遍历作为参数给出的列表:
\documentclass{article}
\newenvironment{definition}[1]
{\def\currentdef{#1}}
{}
\makeatletter
\def\cond#1{\edef\@tempa{#1}%
\@tempswafalse
\@for\@tempb:=\currentdef\do
{\ifx\@tempa\@tempb\@tempswatrue\fi}%
\if@tempswa\else\@tempa\fi
}
\makeatother
\begin{document}
\def\test{test2}
\begin{definition}{test2,test3}
\cond{test3}
\cond{\test}
\cond{test1}
\end{definition}
\end{document}
环境definition
将参数存储在宏中\currentdef
(正如您所做的那样)。宏\cond
完全扩展其参数并将结果存储在中\@tempa
。然后将暂存条件设置为 false,并在与 的每个部分进行比较\@tempswa
的帮助下;块\@for
\@tempa
\currentdef
\@for\@tempb=\LIST\do{<code>}
其中\LIST
扩展为a,b,c
(任何以逗号分隔的标记列表)执行扩展为<code>
,并依次执行。\@tempb
a
b
c
<code>
在我们的例子中, 是“检查和是否具有\@tempa
相同\@tempb
的含义(此处为扩展),如果是,则设置\if@tempswa
为 true。
最后\cond
测试\@iftempswa
:如果为真,则不执行其他任何操作,否则\@tempa
进行扩展。
可以获得相同的效果,但还可以获得一些改进expl3
:
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{definition}{m}
{ \canaaerus_store:n { #1 } } { }
\NewDocumentCommand{\cond}{m}
{ \canaaerus_check:x { #1 } }
\cs_new_protected:Npn \canaaerus_store:n #1
{
\seq_set_split:Nnn \l_canaaerus_list_seq { , } { #1 }
}
\cs_new_protected:Npn \canaaerus_check:n #1
{
\seq_if_in:NnF \l_canaaerus_list_seq { #1 } { #1 }
}
\cs_generate_variant:Nn \canaaerus_check:n { x }
\seq_new:N \l_canaaerus_list_seq
\ExplSyntaxOff
改进之处在于列表周围的空格被删除,因此
\begin{definition}{test2 , test3 }
和没有空格的输入一样好。
策略相同,但参数 todefinition
存储在序列中(作为奖励,列表参数周围的空格被删除)。循环的工作方式与以前类似:我们检查参数 to \canaaerus_check:x
(完全展开)是否出现在序列中;如果没有,则输出该参数。
注意我们如何得到完整的展开:定义的宏是\canaaerus_check:n
,但是我们还创建了一个变体,以便使用
\canaaerus_check:x {<tokens>}
因此几乎相当于说
\edef\@tempa{<tokens>}\expandafter\canaaerus_check:n\expandafter{\@tempa}
(我为 LaTeX3 与原始语法的糟糕混合道歉,但这只是举例而已。)“变体”方法的便利性应该是不言而喻的。