我正在尝试创建一种机制来了解环境中重复命令的次数是否enumerate
存在。
举例来说,使用以下\dummy
命令,这将是一个有效的条目:
\begin{enumerate}
\item Level 1 \dummy{1} OK
\item Level 1 \dummy{2} OK
\end{enumerate}
无效条目为:
\begin{enumerate}
\item Level 1 \dummy{1} OK
\item Level 1 NO dummy here.
\end{enumerate}
由于环境可以嵌套,有效条目可以采用以下形式:
\begin{enumerate}
\item Level 1 \dummy{1} OK
\item Level 1 NO dummy here, dummy in next level
\begin{enumerate}
% Start level 2
\item Level 2 \dummy{2} OK
\item Level 2 NO dummy here, dummy in next level
\begin{enumerate}
% Start level 3
\item Level 3 \dummy{3} OK
\item Level 3 NO dummy here, dummy in next level
\begin{enumerate}
% Start level 4
\item Level 4 \dummy{4} OK
\item Level 4 \dummy{5} OK
\end{enumerate}
\item Level 3 \dummy{6} OK
\end{enumerate}
\item Level 2 \dummy{7} OK
\end{enumerate}
\item Level 1 \dummy{8} OK
\end{enumerate}
对于下一个 MWE,我预计最终输出将是{ TRUE }
\documentclass{article}
\ExplSyntaxOn
% Copy macros
\cs_new_eq:NN \_enumerate_start: \enumerate
\cs_new_eq:NN \_enumerate_stop: \endenumerate
\NewCommandCopy{ \_item_std }{ \item }
% Vars
\int_new:N \g_enumerate_level_int
\int_new:N \g_enumerate_item_int
% Redefine enumerate
\RenewDocumentEnvironment{enumerate}{ }
{
\int_gincr:N \g_enumerate_level_int
\_redefine_item:
\_enumerate_start:
}
{
\_enumerate_stop:
\int_compare:nTF { \g_enumerate_level_int = \g_enumerate_item_int }
{ TRUE }{ FALSE }
}
% Redefine \item
\cs_new_protected:Npn \_redefine_item:
{
\RenewDocumentCommand\item{ o }
{
\int_gincr:N \g_enumerate_item_int
%\int_compare:nT { \g_enumerate_level_int > 1 }
%{
%\int_gsub:Nn \g_enumerate_item_int { 1 }
%}
\tl_if_novalue:nTF {##1}
{
\_item_std%[Item ~ \int_use:N \g_enumerate_item_int]
}
{ \_item_std[##1] }
}
}
\NewDocumentCommand\dummy{ m }
{
\int_gincr:N \g_tmpb_int
\texttt{dummy~#1~=~\int_use:N \g_tmpb_int}
}
\ExplSyntaxOff
\begin{document}
\begin{enumerate}
\item Level 1 \dummy{1} OK % \g_enumerate_item_int = 1
\item Level 1 NO dummy here, dummy in next level
\begin{enumerate}
% Start level 2
\item Level 2 \dummy{2} OK % \g_enumerate_item_int = 2
\item Level 2 NO dummy here, dummy in next level
\begin{enumerate}
% Start level 3
\item Level 3 \dummy{3} OK % \g_enumerate_item_int = 3
\item Level 3 NO dummy here, dummy in next level
\begin{enumerate}
% Start level 4
\item Level 4 \dummy{4} OK % \g_enumerate_item_int = 4
\item Level 4 \dummy{5} OK % \g_enumerate_item_int = 5
\end{enumerate}
\item Level 3 \dummy{6} OK % \g_enumerate_item_int = 6
\end{enumerate}
\item Level 2 \dummy{7} OK % \g_enumerate_item_int = 7
\end{enumerate}
\item Level 1 \dummy{8} OK % \g_enumerate_item_int = 8
\end{enumerate}
\end{document}
我怎样才能实现这个目标?
真实情况是问题/答案列表,目的是检查每个问题是否都有答案。
如果该行以 开头\item
并且没有打开嵌套环境,则它必须有一个\dummy
,如果该行以 开头\item
并且打开嵌套环境,则\item
嵌套环境中的每个都必须有一个
\dummy
。
答案1
这里有一种tokcycle
方法,你可以将外部环境包装在 中\needdummytrue\tokencyclexpress...\endtokencyclexpress
。它...
在执行之前会预先分析 ,如果应该出现在 上但没有出现,或者出现在非预期的地方,则将 插入(MISSING)
到环境中。\dummy
\item
(XTRA)
\dummy
通过删除包装器,测试消失并且环境正常执行。
虽然这个 MWE 不会分析 OP 提供的“有效形式”,但这种方法是使用该输入运行的,并且没有检测到任何错误,正如预期的那样。
\documentclass{article}
\usepackage{tokcycle}
\def\dummy{DD}
\newif\ifneeddummy
\Macrodirective{%
\ifx\item#1\ifneeddummy\addcytoks{(MISSING)}\else\needdummytrue\fi\fi
\ifx\end#1\ifneeddummy\addcytoks{(MISSING)}\fi\fi
\ifx\dummy#1\ifneeddummy\needdummyfalse\else\addcytoks{(XTRA)}\fi\fi
\ifx\begin#1\ifneeddummy\needdummyfalse\else\addcytoks{(XTRA)}\fi\fi
\addcytoks{#1}%
}
\begin{document}
\needdummytrue\tokencyclexpress
\begin{itemize}
\item \dummy
\item no dummy
\begin{enumerate}
\item \dummy
\item no dummy
\item \dummy
\end{enumerate}
\item \dummy \dummy
\item \dummy
\begin{enumerate}
\item \dummy
\end{enumerate}
\end{itemize}
\endtokencyclexpress
\end{document}
如果我注释掉包装行,我会得到相同的输出,但诊断消息被删除了。当然,如果没有注意到运行诊断的警告,输出可能会包含错误。
答案2
可能的解决方案(经过我的测试)并且符合我的需要:)
\documentclass{article}
\ExplSyntaxOn
% Copy macros
\cs_new_eq:NN \_enumerate_start: \enumerate
\cs_new_eq:NN \_enumerate_stop: \endenumerate
\NewCommandCopy{ \_item_std }{ \item }
% Vars
\int_new:N \g_enumerate_tempa_int
\int_new:N \g_enumerate_tempb_int
\int_new:N \g_enumerate_tempc_int
\int_new:N \l_enumerate_level_int
\int_new:N \g_enumerate_count_item_all_int
% Redefine enumerate
\RenewDocumentEnvironment{enumerate}{ }
{
\int_incr:N \l_enumerate_level_int
\_enumerate_start:
\_redefine_item:
\int_case:nn{ \l_enumerate_level_int }
{
{ 2 }{ \int_gincr:N \g_enumerate_tempa_int }
{ 3 }{ \int_gincr:N \g_enumerate_tempb_int }
{ 4 }{ \int_gincr:N \g_enumerate_tempc_int }
}
}
{ \_enumerate_stop: }
% Redefine \item
\cs_new_protected:Npn \_redefine_item:
{
\RenewDocumentCommand\item{ o }
{
\int_gincr:N \g_enumerate_count_item_all_int
\tl_if_novalue:nTF {##1} { \_item_std } { \_item_std[##1] }
}
}
\NewDocumentCommand\dummy{ m }
{
\int_gincr:N \g_tmpb_int
\texttt{dummy~#1~=~\int_use:N \g_tmpb_int}
}
\NewDocumentCommand\test{ }
{
\int_gset:Nn \g_tmpa_int
{
\g_enumerate_count_item_all_int - \g_enumerate_tempa_int
- \g_enumerate_tempb_int - \g_enumerate_tempc_int
}
% \int_show:N \g_tmpa_int
\int_compare:nTF { \g_tmpa_int = \g_tmpb_int }
{ \typeout{TRUE} }{ \typeout{FALSE} }
}
\ExplSyntaxOff
\begin{document}
\begin{enumerate}
\item Level 1 \dummy{1}
\item Level 1 NO dummy
\begin{enumerate}
\item Level 2 \dummy{2}
\item Level 2 NO dummy
\begin{enumerate}
\item Level 3 \dummy{3}
\item Level 3 NO dummy
\begin{enumerate}
\item Level 4 \dummy{4}
\item Level 4 \dummy{5}
\end{enumerate}
\item Level 3 \dummy{6}
\end{enumerate}
\item Level 2 NO dummy
\begin{enumerate}
\item Level 3 \dummy{7}
\item Level 3 NO dummy
\begin{enumerate}
\item Level 4 \dummy{8}
\item Level 4 \dummy{9}
\end{enumerate}
\item Level 3 \dummy{10}
\end{enumerate}
\item Level 2 \dummy{11}
\end{enumerate}
\item Level 1 \dummy{12}
\item Level 1 \dummy{13}
\item Level 1 NO dummy
\begin{enumerate}
\item Level 2 \dummy{14}
\item Level 2 NO dummy
\begin{enumerate}
\item Level 3 \dummy{15}
\end{enumerate}
\item Level 2 \dummy{16}
\end{enumerate}
\end{enumerate}
% TRUE
\test
\end{document}