我想\item
暂时重新定义,但也想让它表现得像普通的 \item
应该。所以,我认为通过严格遵循 的定义\item
,我会得到我想要的结果。但是以下 MWE 无法识别可选参数。
\documentclass{article}
\pagestyle{empty}
\begin{document}
\begin{enumerate}
\begingroup
\makeatletter
\def\item{\@ifnextchar [\@item{\@noitemargtrue \@item[\@itemlabel]} \rule[-2ex]{0.8pt}{5ex}\endgroup}%%'
\makeatother
\item[test] A
\item B
\item C
\item D
\end{enumerate}
\end{document}
为什么会失败?
答案1
看一下\@ifnextchar
(取自latex.ltx
):
\long\def\@ifnextchar#1#2#3{%
\let\reserved@d=#1%
\def\reserved@a{#2}%
\def\reserved@b{#3}%
\futurelet\@let@token\@ifnch}
它将三个参数存储在由 标识的三个单独的宏中\reserved@?
。然后,它调用\futurelet\@let@token\@ifnch
。 的行为\futurelet
(如中所述)在哪里可以找到\futurelet
有关 的恶劣行为的记录?) 是:
TeX 还允许构造
\futurelet\cs<token1><token2>
,其效果为\let\cs = <token2><token1><token2>
。
在一个简化的情况下,重新\item
定义任何事物后续\@ifnextchar
施工会造成问题,以后<token2>
就不会再有[
。
如何解决这个限制?不要\@ifnextchar
直接使用。下面是一种使用传统方法的简单方法\renewcommand
:
\documentclass{article}
\pagestyle{empty}
\begin{document}
\begin{enumerate}
\begingroup
\makeatletter
\let\olditem\item
\renewcommand{\item}[1][\@empty]{%
\ifx#1\@empty
\olditem%
\else
\@item[#1] \rule[-2ex]{0.8pt}{5ex}\endgroup%
\fi}%
\makeatother
\item[abc] A
\item B
\item[xyz] C
\item D
\end{enumerate}
\end{document}
答案2
作为沃纳指出,您不能在 '之后' 添加任何内容\@ifnextchar
。您还需要确保 后面\@item
跟着[
,因此您不能只将规则添加到结果的两个分支\@ifnextchar
。同时,如果可能的话,我会避免使用\begingroup
外部宏和\endgroup
内部宏。这导致了以下形式的解决方案:
\documentclass{article}
\usepackage{etoolbox}
\pagestyle{empty}
\tracingpatches
\begin{document}
\begin{enumerate}
\let\origitem\item
\makeatletter
\let\orig@item\@item
\patchcmd{\@item}{\ignorespaces}
{%
\rule[-2ex]{0.8pt}{5ex}%
\let\@item\orig@item
\ignorespaces
}
{}{}
\def\item{%
\let\item\origitem
\@ifnextchar [%]
\@item
{\@noitemargtrue \@item[\@itemlabel]}%
}
\makeatother
\item[test] A
\item B
\item C
\item D
\end{enumerate}
\end{document}
请注意,使用\item
将恢复原始定义,使用 也是如此\@item
,但没有组。
答案3
虽然在最初的问题中没有提到,但最终我想要一些更动态的东西:也就是说,我希望重新定义\item
能够持续存在,而不仅仅是第一次出现。我还想要一些行为符合预期如果嵌套在另一个列表中。
在看到@werner 和@wright 的解决方案之前,我最终得出的结论是:
\documentclass{article}
\makeatletter
\let\ae@original@item\item
\newenvironment{myenum}[1]
{\begin{enumerate}
\let\item\ae@original@item
\def\ae@how@far@advanced{1}%%'
\newif\ifae@unfinished@
\begingroup
\ae@unfinished@true
\def\ae@item[##1]{%%'
\@item[##1] \rule[-2ex]{0.8pt}{5ex}%%'
\ifnum\ae@how@far@advanced=#1\relax
\ae@unfinished@false\endgroup
\fi
\edef\ae@how@far@advanced{\number\numexpr\ae@how@far@advanced+1\relax}\ignorespaces}
\def\item{\@ifnextchar [%%]
\ae@item{\@noitemargtrue \ae@item[\@itemlabel]}}%%'
}%%'
{\ifae@unfinished@\endgroup\fi
\end{enumerate}}
\makeatother
\begin{document}
\begin{myenum}{5}
\item A
\item [test] B
\item C
\begin{myenum}{2}
\item Bc
\item A
\item C
\item D
\end{myenum}
\item D
\item E
\item F
\end{myenum}
\end{document}
我想那\ae@how@far@advanced
可能真的是一个计数器。但是,我还是需要一些东西,因为我计算的是 的出现次数,\item
而不是 (和家族) 的值,使用enumi
时不会提前。\item[...]
我喜欢提供的两种解决方案。@wright 的解决方案很好地展示了如何避免使用\begingroup
和\endgroup
。但是,我宁愿不调用另一个包。@werner 的解决方案非常优雅,它避免了调用\@ifnextchar
并设法测试空的争论。
我选择发布自己的解决方案,因为我最终看到了自己的
- 误解何时以及什么正在扩大,
- 误解是
\@ifnextchar
永远不会看到我的宏之后的下一个字符,因为我已经抛出了很多噪音挡住路。
但我能够找到解决方案\@ifnextchar
并正确地重定向事物。