考虑以下使用命令简单嵌套两个列表的代码\ForEach
:
\documentclass{article}
\usepackage{forarray}
\newcommand{\demo}[1]
{
\begin{itemize}
\ForEach{.}{\item \thislevelitem}{#1}
\end{itemize}
}
\begin{document}
\demo
{
1.
\demo
{
21.
22
}.
3
}
\end{document}
我应该如何修改\demo
命令,以便如果我删除.
之前的3
,输出保持不变?
其动机是复制一种通常的编程语言语法,其中语句以 结尾,.
并且控制序列(例如\demo
)括在括号之间(没有最后的.
)。
您可以随意使用您喜欢的列表处理工具,forarray
但请尽量避免使用Expl3
语法。
答案1
这是解决方案的草稿。我相信这可以稍微整理一下,但这是我目前想到的:
\documentclass{article}
\usepackage{forarray}
\makeatletter
\def\@demo@query{\relax}%%
\newcounter{@demo@level@cnt}
\newcommand{\demo}[1]{\@demo#1\@demo@query\@nil\@demo@follow@up}
\def\@demo#1\@nil{%%
\stepcounter{@demo@level@cnt}%%
\begin{itemize}
\ForEach{.}{\item \thislevelitem}{#1}%%
}
\def\@demo@follow@up{%%
\@ifnextchar\@demo@query
{\@demo@close}
{\@demo@continue}}
\def\@demo@continue{%%
\@demo@close
\ifnum\the@demo@level@cnt>0 %%
\item
\fi
}
\def\@demo@close{%%
\end{itemize}%%
\addtocounter{@demo@level@cnt}{-1}%%
}
\makeatother
\begin{document}
\demo
{
1.
\demo
{
21.
22
}
3.4
}
\rule{\textwidth}{0.4pt}
\demo
{
1.
\demo
{
21.
22
}}
\rule{\textwidth}{0.4pt}
\demo
{
1.
\demo
{
21.
22
}
}
\end{document}
关键是创建一些包装器代码来绕过 引入的包装器代码forarray
。因此
\@demo#1\@demo@query\@nil\@demo@follow@up
最后一个命令
\@demo@follow@up
接下来是
\@demo@query
仅当没有进一步的代码需要检查时。
帮助了解正在发生的事情 考虑以下有争议的代码:
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\makeatletter
\newcommand\demo[1]{\@demo#1?\@nil!}
\def\@demo#1\@nil{[\another{#1}]}
\def\another#1{<<#1>>}
\makeatother
\begin{document}
\ttfamily
\demo{1.\demo{21.22}3.4}\par
\demo{1.\demo{21.22}}
\end{document}
该宏用和\another
包装其参数,其方式与宏类似。问号充当 的角色,感叹号充当 的角色。与上面的实际解决方案一样,只有在没有要考虑的后续代码时, 才会出现在 之前。<<
>>
forarray
\@demo@query
\@demo@follow@up
!
?
\ForEach