阅读这个问题@Werner 的回答让我思考是否有可能拥有自定界宏链,例如,\XX abc \XX def \XX xyz
或者说
\begin{someenv}
\XX abc
\XX def
\XX xyz
\end{someenv}
最初的定义显然会在这里失败——数量不足\XX
。因此,重新定义的第一个步骤\XX
可能是
\def\XX#1\XX{do sth with #1\\ \XX}
现在的问题是如何优雅地结束这个链条。一个相当粗鲁和不是理想的方式如下面的MWE所示。
\documentclass{article}
\def\XX#1\XX{do sth with #1\\ \XX}
\newenvironment{someenv}{\center}{\endcenter}
\def\abc{def}
\begin{document}
\begin{someenv}
\XX xyz
\XX abc
\XX \abc
\let\XX\empty %this is the bad guy that needs to be busted
\end{someenv}
\end{document}
答案1
除非您获取所需的令牌列表作为参数,否则您无法真正做到这一点。
这是一种使用的可能性environ
;使用expl3
不是必需的,但它为以后完成所需的工作提供了一个很好的框架。
\documentclass{article}
\usepackage{environ,expl3}
\ExplSyntaxOn
\NewEnviron{collectitems}
{
% clear the sequence
\seq_clear:N \l_ruben_collected_items_seq
% process the body
\exp_last_unbraced:No \ruben_collect_item:nw \BODY \item \q_stop
% do something with the sequence
\seq_show:N \l_ruben_collected_items_seq
}
\seq_new:N \l_ruben_collected_items_seq
\cs_new_protected:Npn \ruben_collect_item:nw #1 \item #2 \q_stop
{
\seq_put_right:Nx \l_ruben_collected_items_seq { \tl_trim_spaces:n { #1 } }
\tl_if_empty:nF { #2 }
{
\ruben_collect_item:nw #2 \q_stop
}
}
\ExplSyntaxOff
\begin{document}
\begin{collectitems}
\item Apple
\item Banana
\item Cherry
\end{collectitems}
\begin{collectitems}
\end{collectitems}
\end{document}
主体收集在 中,在添加和\BODY
之前进行扩展。该函数在每个 时执行,直到后紧接着。项目按顺序排列;序列中的第一个项目将包含第一个标记之前的内容,可用于检查标记是否真正可见,如示例所示。\ruben_collect_item:nw
\item \q_stop
\ruben_collect_item:nw
\item
\item
\q_stop
\item
\item
终端上的输出是
The sequence \l_ruben_collected_items_seq contains the items (without outer braces):
> {}
> {Apple}
> {Banana}
> {Cherry}.
<recently read> }
l.31 \end{collectitems}
?
The sequence \l_ruben_collected_items_seq contains the items (without outer braces):
> {}.
<recently read> }
l.34 \end{collectitems}
当然,您可以利用该序列做一些更有用的事情。
将描述环境的左边距“翻译”为经典命令,使左边距适应最宽标签的宽度。
\documentclass{article}
\usepackage{environ,enumitem}
\newlength\rubenwidth
\NewEnviron{xdescription}{%
\expandafter\rubenprocess\BODY\item\rubenprocess
\begin{itemize}[labelwidth=\rubenwidth,leftmargin=\rubenwidth,align=left,font=\bfseries]
\BODY
\end{itemize}
}
\makeatletter
\def\rubenprocess#1#2\item#3\rubenprocess{% #1 is always \item
\ruben@item#2\ruben@item
\if\relax\detokenize{#3}\relax
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{\rubenprocess\item#3\rubenprocess}%
}
\def\ruben@item[#1]#2\ruben@item{%
\settowidth\@tempdima{\bfseries#1}%
\ifdim\rubenwidth<\@tempdima\rubenwidth=\@tempdima\fi
}
\begin{document}
\begin{xdescription}
\item[Apple] a round fruit
\item[Banana] not so round fruit
\item[Strawberry] small fruit with some more words
to get the text into two lines; will we succeed?
\end{xdescription}
\end{document}
该想法有多种可能的变化。
答案2
这就是你想要的东西吗?
\documentclass{article}
\newenvironment{someenv}{\par\centering}{\par}
\newenvironment{XX}{\endXX\bfseries\itshape Do sth with\ }{\mdseries\upshape\par}
\let\notXX\endXX
\def\abc{ABC}
\begin{document}
before
\begin{someenv}
\XX xyz
\XX abc
\XX \abc
\notXX not under \verb|\XX| control % USE \notXX TO FORCE BREAK FROM \XX CONTROL
\XX ending line
\end{someenv}
after
\end{document}
你可以发挥想象力,制作出随着环境\XX
的迭代而变化的“东西” 。\XX
\documentclass{article}
\newcounter{instance}
\newenvironment{someenv}{\par\centering\setcounter{instance}{0}}{\par}
\newenvironment{XX}{\endXX\bfseries\itshape\stepcounter{instance}
Iteration \theinstance: Do sth with\ }
{\mdseries\upshape\par}
\let\notXX\endXX
\def\abc{ABC}
\begin{document}
before
\begin{someenv}
\XX xyz
\XX abc
\XX \abc
\notXX not under \verb|\XX| control % USE \notXX TO FORCE BREAK FROM \XX CONTROL
\XX ending line
\end{someenv}
after
\end{document}
答案3
您可以使用以下代码宏参数由多个分隔符分隔。此代码定义\seplist
宏。其参数是分隔符列表。您的示例中的分隔符是\XX
或\end
(前面有空格)。的定义\XX
如下所示:
\def\XXa#1{... macro with normal #1 parameter\par\sepused}
\def\XX{\seplist{{ \XX}{ \end}}\XXa}
\begin{someenv}
\XX abc
\XX def
\XX xyz
\end{someenv}