考虑以下代码
\documentclass{article}
\usepackage{xstring,etoolbox}
\usepackage[shortlabels]{enumitem}
\def\lists{%
parts-a),
items-1)
}
\renewcommand*{\do}[1]{%
\StrCut{#1}{-}\csA\csB
% the next line is the "crucial one"
\expandafter\providecommand\csname my\csA\endcsname[1][\csB]{%
\begin{enumerate}[##1]
\item one
\item two
\end{enumerate}
}
}
\expandafter\docsvlist\expandafter{\lists}
\begin{document}
\myparts[i)]
\myparts
\end{document}
它产生
i) one
ii) two
1) one
1) two
我应该如何修改“关键线”,以使其按预期工作,即产生
i) one
ii) two
a) one
b) two
?
据我所知,我需要传递 \csB“expanded”。但我玩了几个小时各种 edef 和 expandafter,我快要疯了,我已经没有主意了。
(以上是一个精简的最小示例 - 实际上它是一个更有用的代码,但我认为以上很好地解决了我的问题)
编辑:siracusa 的答案似乎有效,不幸的是我不知道如何通过以下修改来做一个更困难的例子
\begin{enumerate}[##1]
\item one
\item two
\end{enumerate}
The above list is of type \csB
如上所述,它将始终打印“以上列表属于类型 1)”,并且我不清楚如何修改 siracusa 的答案以正确扩展 \myparts 定义中的 \csB...
答案1
以下似乎就是您想要的:
\renewcommand*{\do}[1]{%
\StrCut{#1}{-}\csA\csB
% the next line is the "crucial one"
\edef\temp{\noexpand\providecommand\expandafter\noexpand\csname my\csA\endcsname[1][\csB]}%
\temp{%
\begin{enumerate}[##1]
\item one
\item two
\end{enumerate}
}
}
我们首先定义一个临时命令\temp
,该命令将参数完全展开\providecommand
,除了\providecommand
被 阻止的宏本身\noexpand
。然后\temp
执行 来实际执行命令定义。
这是有关扩展问题的新版本:
\renewcommand*{\do}[1]{%
\StrCut{#1}{-}\csA\csB
% the next line is the "crucial one"
\edef\temp{\noexpand\providecommand\expandafter\noexpand\csname my\csA\endcsname[1][\csB]{%
\noexpand\begin{enumerate}[####1]
\noexpand\item one
\noexpand\item two
\noexpand\end{enumerate}
The above list is of type \csB
}%
}\temp
}
now涵盖\edef
整个定义,而不仅仅是参数。但是,这使得必须为所有不应被扩展的命令添加前缀\noexpand
。不确定这在您的实际代码中是否可行。egregxparse
建议的版本在这里更灵活。
答案2
您不应该使用\providecommand
这个。此外,重新定义\do
非常危险,因为多个包可以使用它。etoolbox
您可以使用\forcsvlist
,它接受不同的宏。
主要问题是传球\csB
扩大。
\documentclass{article}
\usepackage{xstring,etoolbox}
\usepackage[shortlabels]{enumitem}
\newcommand\lists{%
parts-a),
items-1)
}
\newcommand*{\mydo}[1]{%
\StrCut{#1}{-}\csA\csB
% build \newcommand one step at a time
\toks0=\expandafter{\expandafter\newcommand\csname my\csA\endcsname}%
\toks2=\expandafter{\csB}%
\begingroup\edef\x{\endgroup\the\toks0[1][\the\toks2]}\x{%
\begin{enumerate}[##1]
\item one
\item two
\end{enumerate}
}%
}
\expandafter\forcsvlist\expandafter\mydo\expandafter{\lists}
\begin{document}
\myparts[i)]
\myparts
\end{document}
采用不同的方法,基于xparse
:
\documentclass{article}
\usepackage{xparse}
\usepackage[shortlabels]{enumitem}
\NewDocumentCommand{\parselists}{>{\SplitList{,}}m}{%
\ProcessList{#1}{\makelist}%
}
\NewDocumentCommand{\makelist}{>{\SplitArgument{1}{-}}{m}}{%
\makelistsdo#1%
}
\NewDocumentCommand{\makelistsdo}{mm}{%
\NewDocumentNamedCommand{my#1}{O{#2}}{%
\begin{enumerate}[##1]
\item one
\item two
\end{enumerate}
}%
}
\ExplSyntaxOn
\cs_new_protected:Npn \NewDocumentNamedCommand #1
{
\exp_args:Nc \NewDocumentCommand { #1 }
}
\ExplSyntaxOff
\parselists{
parts-a),
items-1),
}
\begin{document}
\myparts[i)]
\myparts
\myitems[i)]
\myitems
\end{document}