我希望有一种方法可以检测特定宏的参数是否包含该特定宏本身。考虑以下 MNWE:
\documentclass{article}
\usepackage{etoolbox}
\newcommand*{\hasself}[1]{%
#1 \ifboolexpr{
% what goes here?
}{1}{0}%
}
\begin{document}
This should return `Test 1 0': \hasself{Test\hasself{}}
This should return `Test 0': \hasself{Test}
\end{document}
要使这个功能起作用,布尔测试应该是什么?或者还有其他方法可以实现相同的目标吗?
用例是 LaTeX2e,但我也愿意看到 Plain TeX、LaTeX3、LaTeX4 等解决方案。
如果可能的话,我希望解决方案可以在参数的任何分组级别上工作。如果这会产生影响,您可以假设参数不会\long
(所以我想我真的可以\newcommand*
在 MNWE 中使用:已更新)。对于我的使用来说,没有必要捕捉等效\def
宏,但如果有可能的话,看到它会很好。
答案1
由于counters
LaTeX 中是全局量,我决定使用它们来解决您的问题。这并不能完全满足您的要求,因为它先打印最内层的结果,然后再打印嵌套中最外层的结果。这意味着,对于您的第一个示例,输出是“0 1”而不是“1 0”。但我认为,对于您想要使用它的目的,这可能是可以接受的。
输出实际上是递归的级别。
\documentclass{article}
\usepackage{etoolbox}
\newcounter{hcount}
\newcommand*{\hasself}[1]{%
\addtocounter{hcount}{-1}%
\edef\hbefore{\thehcount}%
#1\ %
\the\numexpr\thehcount-\hbefore\relax%
\addtocounter{hcount}{1}%
}
\def\junk#1{\hasself{#1}}
\begin{document}
This should return `Test 1 0': \hasself{Test\hasself{}}
This should return `Test 0': \hasself{Test}
\hasself{Test\hasself{Test\hasself{}}}
\hasself{Test\junk{Test\hasself{}}}
\end{document}
答案2
Steven 的解决方案基于参数被处理的事实。我在这里展示了另一种解决方案:参数仅逐个标记进行扫描。该解决方案基于以下代码:OPmac 技巧 www 页面。这里只需添加几行即可实现实际任务。
%% the code from http://petr.olsak.net/opmac-tricks-e.html#readtoks :
\newtoks\readtoksT \newif\ifreadtoksG
\def\readtoks{\begingroup \let\bgroup=\relax \let\egroup=\relax
\readtoksT={}\readtoksGfalse \afterassignment\readtoksA \let\next= }
\def\readtoksA{\futurelet\tmpc\readtoksB}
\def\readtoksB{\let\next=\readtoksD \csname readtoksX\endcsname
\ifcat\space\noexpand\tmpc \let\next=\readtoksC \def\nexxt{\readtoksD{ }}\fi
\ifcat{\noexpand\tmpc \let\next=\readtoksC \let\nexxt=\readtoksE \fi
\ifcat}\noexpand\tmpc \let\next=\readtoksC \let\nexxt=\readtoksF \fi
\next
}
\def\readtoksC{\afterassignment\nexxt \let\next= }
\def\readtoksD#1{\readtoksT=\expandafter{\the\readtoksT#1}\readtoksA}
\def\readtoksE{\begingroup \readtoksGtrue \readtoksT={}\readtoksA}
\def\readtoksF{\ifreadtoksG
\expandafter\endgroup\expandafter\readtoksT\expandafter\expandafter\expandafter
{\expandafter\the\expandafter\readtoksT\expandafter{\the\readtoksT}}%
\expandafter\readtoksA
\else
\expandafter\endgroup\expandafter\readtoksO\expandafter{\the\readtoksT}%
\fi
}
\def\readtoksO{\toks1}
%% The code for this actual task:
\newif\iftokenfound
\def\testtoken#1#2{{\global\tokenfoundfalse
\def\readtoksX{\ifx\tmpc#1\global\tokenfoundtrue\fi}%
\readtoks{#2}%
}}
\def\hasself#1{\testtoken\hasself{#1}%
\iftokenfound Yes, hasself is present.
\else hasself isn't present.
\fi
}
%%% Test:
NO: \hasself{Normal {text}}
YES: \hasself{Special {text \hasself{in group}}}
\bye