我在递归使用宏时遇到了一些麻烦\@ifnextchar
。我的目标是能够在或环境\subitem{item1}{item2}...{itemN}
中调用。这是我目前所拥有的,但它只拾取了第一个参数。enumerate
itemize
\makeatletter
\newcommand{\checknextarg}{\@ifnextchar\bgroup{\gobblenextarg}{}}
\newcommand{\gobblenextarg}[1]{ \item #1\checknextarg}
\newcommand*\@enumerate{enumerate}
\newcommand*\@itemize{itemize}
\renewcommand{\subitem}[1]{%
\ifx\@currenvir\@enumerate
\begin{enumerate}
\item #1\checknextarg
\end{enumerate}
\else
\ifx\@currenvir\@itemize
\begin{itemize}
\item #1\checknextarg
\end{itemize}
\fi
\fi
}
\makeatother
例如
\begin{enumerate}
\item foo
\subitem{bar}{baz}
\end{enumerate}
生产
答案1
在这里我使用了一个标记循环(一种递归循环输入流的标记的工具),并带有以下指令:
如果下一个标记是字符或宏(即控制序列),则结束标记循环 + 结束子枚举 + 将下一个标记恢复到输入流
如果下一个 token 是 cat-1 组,则应用于
\item
该组内容如果下一个标记是空格,则忽略它。
MWE 证明了当\subenumerate
出现在项目中间、项目之间或枚举末尾时的有效性。
这里,我没有区分 itemize 和 enumerate,而只是求解了。可以构造enumerate
一个等价的。\subitemize
\documentclass{article}
\usepackage{tokcycle}
\Characterdirective{\tcpush{\noexpand\endtokcycraw\end{enumerate}#1}}
\Groupdirective{\item{#1}}
\Macrodirective{\tcpush{\noexpand\endtokcycraw\end{enumerate}#1}}
\Spacedirective{}
\newcommand\subenumerate{\begin{enumerate}\tokencyclexpress}
\begin{document}
\begin{enumerate}
\item foo1
\subenumerate{bar}{baz}
continue foo
\item foo2
\subenumerate{bar2}{baz2}
\item foo3
\subenumerate{bar3} {baz3}
\end{enumerate}
End of enumerate
\end{document}
或者,可以将标记循环指令合并到宏定义本身中:
\documentclass{article}
\usepackage{tokcycle}
\newcommand\subenumerate{\begin{enumerate}\tokencycle
{\tcpush{\noexpand\endtokencycle\end{enumerate}##1}}%CHARS
{\item{##1}}%GROUPS
{\tcpush{\noexpand\endtokencycle\end{enumerate}##1}}%MACROS
{}%SPACES
}
\begin{document}
\begin{enumerate}
\item foo1
\subenumerate{bar}{baz}
continue foo
\item foo2
\subenumerate{bar2}{baz2}
\item foo3
\subenumerate{bar3} {baz3}
\end{enumerate}
End of enumerate
\end{document}
答案2
我警告你不要这么做。它破坏了 LaTeX 的所有已知语法(如果你想创建索引,就会遇到问题)。
\documentclass{article}
\makeatletter
\newcommand{\check@next@arg}{\@ifnextchar\bgroup{\another@item}{\finish@up}}
\newcommand{\another@item}[1]{\item #1\check@next@arg}
\renewcommand{\subitem}{%
\edef\finish@up{\noexpand\end{\@currenvir}}%
\expandafter\begin\expandafter{\@currenvir}%
\check@next@arg
}
\makeatother
\begin{document}
\begin{enumerate}
\item foo
\subitem{bar}{baz}
\end{enumerate}
\begin{itemize}
\item foo
\subitem{bar}{baz}{whatever}
\end{itemize}
\end{document}
你的错误是什么?你吸收了第一个参数,当你的\checknextarg
命令进入场景时,它会找到\end
下一个标记。
我更喜欢显式标记。但是,这里有一个略有不同的版本,它允许选择不同的列表类型,并使用在 处拆分的单个参数\\
。
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\sublist}{om}
{
\IfNoValueTF { #1 }
{
\richbai_sublist:vn { @currenvir } { #2 }
}
{
\richbai_sublist:nn { #1 } { #2 }
}
}
\seq_new:N \l__richbai_sublist_items_seq
\cs_new_protected:Nn \richbai_sublist:nn
{
\begin{#1}
\seq_set_split:Nnn \l__richbai_sublist_items_seq { \\ } { #2 }
\item \seq_use:Nn \l__richbai_sublist_items_seq { \item }
\end{#1}
}
\cs_generate_variant:Nn \richbai_sublist:nn { v }
\ExplSyntaxOff
\begin{document}
\begin{enumerate}
\item foo
\sublist{bar \\ baz}
\end{enumerate}
\begin{itemize}
\item foo
\sublist[enumerate]{bar \\ baz \\ whatever}
\item bar
\end{itemize}
\begin{itemize}
\item foo
\sublist{bar \\ baz \\ whatever}
\item bar
\end{itemize}
\end{document}