使用 enumitem 的 \AddEnumerateCounter* 即时创建新的计数器格式

使用 enumitem 的 \AddEnumerateCounter* 即时创建新的计数器格式

美学警告:我实际上使用的是悬挂数字而非衬线的小型大写字母。然而,在创建一个最小示例时,我屈服于默认设置并创建了一个排版怪物。


我正在尝试创建一个具有类似以下语法的环境:

\begin{<environment name>}{<single letter>}[<options>}
  \item <stuff>
\end{<environment name>}

我希望列表被枚举,并且我希望每个项目都带有标签\textsc{<single letter>}\arabic{<number of item>}.

这很简单enumitem。例如,我可以这样做:

\NewDocumentEnvironment{letters}{ O {} m }{%
  \begin{enumerate}[label=\textsc{#2}\arabic*., ref=\textsc{#2}\arabic*, #1]
}{%
  \end{enumerate}%
}

进而

\begin{letters}{a}
  \item first
  \item second
\end{letters}

将产生

sample 1

但是,当我引用某项时,我希望引用的格式为\textsc{<letter>}\arabic{<value>}(不带点)。同样,这很好,上面的refinenumitem很好地解决了这个问题。

但是,我还希望能够在引用出现在句子开头时将字母大写。fancyref和都cleveref提供这种功能,但是使用小型大写字母表示小写字母会造成问题。

于是我开始调查enumitem,并开始摆弄\AddEnumerateCounter(*)。据我所知,这个命令并没有起到任何作用。相反,它似乎添加了一个计数器格式例如,它是将模拟量添加到\arabic而不是 模拟量到c@page。话虽如此,我一点也不确定我是否理解了它。

我确实设法用以下代码重现了我现有的结果

\makeatletter
\def\csimplelettered#1{\expandafter\@csimplelettered\csname c@#1\endcsname}
\def\@csimplelettered#1{\@arabic#1}
\makeatother
\AddEnumerateCounter{\csimplelettered}{\@csimplelettered}{2}
\NewDocumentEnvironment{simplelettered}{ O {} m }{%
  \begin{enumerate}[label=\textsc{#2}\csimplelettered*., ref=\textsc{#2}\csimplelettered*, #1]
}{%
  \end{enumerate}%
}

这让我可以写

\begin{simplelettered}{b}
  \item first
  \item second
\end{simplelettered}

生产

second sample

因此,我尝试在环境定义中动态创建一个新的计数器格式。以下是一次(肯定很可笑的)尝试

\makeatletter
\NewDocumentEnvironment{lettered}{ O {} m }{%
  \expandafter\def\csname clettered#2\endcsname ##1{\expandafter\expandafter\expandafter\csname @clettered#2\endcsname\csname c@##1\endcsname}%
  \expandafter\def\csname @clettered#2\endcsname ##1{\@arabic##1}%
  \AddEnumerateCounter*{\expandafter\csname clettered#2\endcsname}{\expandafter\csname @clettered#2\endcsname}{2}%
  \begin{enumerate}[label=\textsc{#2}\arabic*., ref=\textsc{#2}\arabic*, #1]
}{%
  \end{enumerate}%
}
\makeatother

显然,我\expandafter在任意位置随机抛出 s 的默认策略在这种特殊情况下并没有特别有效。

现在我对这个问题的兴趣比对原来的问题(我可以用另一种方式解决)更浓厚。我怎样才能使lettered环境工作,以便它创建新的计数器格式并在枚举中使用它?

完成 NMWE:

\documentclass{article}
\usepackage{xparse,enumitem}
\NewDocumentEnvironment{letters}{ O {} m }{%
  \begin{enumerate}[label=\textsc{#2}\arabic*., ref=\textsc{#2}\arabic*, #1]
}{%
  \end{enumerate}%
}
\makeatletter
\def\csimplelettered#1{\expandafter\@csimplelettered\csname c@#1\endcsname}
\def\@csimplelettered#1{\@arabic#1}
\makeatother
\AddEnumerateCounter{\csimplelettered}{\@csimplelettered}{2}
\NewDocumentEnvironment{simplelettered}{ O {} m }{%
  \begin{enumerate}[label=\textsc{#2}\csimplelettered*., ref=\textsc{#2}\csimplelettered*, #1]
}{%
  \end{enumerate}%
}
\makeatletter
\NewDocumentEnvironment{lettered}{ O {} m }{%
  \expandafter\def\csname clettered#2\endcsname ##1{\expandafter\expandafter\expandafter\csname @clettered#2\endcsname\csname c@##1\endcsname}%
  \expandafter\def\csname @clettered#2\endcsname ##1{\@arabic##1}%
  \AddEnumerateCounter*{\expandafter\csname clettered#2\endcsname}{\expandafter\csname @clettered#2\endcsname}{2}%
  \begin{enumerate}[label=\textsc{#2}\arabic*., ref=\textsc{#2}\arabic*, #1]      
  % want to use something like:
  %\begin{enumerate}[label=\textsc{\csname clettered#2\endcsname*}., ref=\csname clettered#2\endcsname*, #1]
}{%
  \end{enumerate}%
}
\makeatother
\begin{document}
\begin{letters}{a}
  \item first
  \item second
\end{letters}
\begin{simplelettered}{b}
  \item first
  \item second
\end{simplelettered}
\begin{lettered}{c}
  \item first
  \item second
\end{lettered}
\end{document}

答案1

我不明白这个问题,所以不要指望这能回答它。但无论如何,如果你用这个代替

\expandafter\def\csname clettered#2\endcsname ##1{\expandafter\expandafter\expandafter\csname @clettered#2\endcsname\csname c@##1\endcsname}%
\expandafter\def\csname @clettered#2\endcsname ##1{\@arabic##1}%
\AddEnumerateCounter*{\expandafter\csname clettered#2\endcsname}{\expandafter\csname @clettered#2\endcsname}{2}%

\def\clettered##1{\expandafter\@clettered\csname c@##1\endcsname}%
\def\@clettered{\@arabic}%
\AddEnumerateCounter*{\clettered}{\@clettered}{2}%

它确实可以编译。除了你不需要定义任何变体之外,因为\csname..\endcsname你处于环境中(如果这与问题无关,请忽略它)。


无论如何,这是您正确使用的解决方案\expandafters

\expandafter\def\csname clettered#2\endcsname##1{\csname @clettered#2\expandafter\endcsname\csname c@##1\endcsname}%
\expandafter\def\csname @clettered#2\endcsname##1{\@arabic{##1}}%
\expandafter\AddEnumerateCounter\expandafter*\csname clettered#2\expandafter\endcsname\csname @clettered#2\endcsname{2}%

为了解释这一点,你只需要一个\expandafter在之前\endcsname创建一个令牌,然后从下一个\csname开始

\csname a\expandafter\endcsname\csname b\endcsname

会先创造\b,然后\a离开\a\b

答案2

我不确定我是否理解了这个问题,但我认为最好的方法是保存未格式化的标签:

\documentclass{article}

\usepackage{enumitem}

\makeatletter
\newcommand\mylabel[2]{\mylabelfont{#1}\@arabic{#2}}
\makeatother
\let\mylabelfont\textsc % Default
\newcommand\ucref[1]{%
  {\let\mylabelfont\MakeUppercase\ref{#1}}}

\begin{document}

\begin{enumerate}[label=\textsc{a}\arabic*,ref=\protect\mylabel{a}{\arabic*}]
\item \label{1st} First
\item \label{2nd} Second
\end{enumerate}

First is \ref{1st} and second is \ref{2nd}. But compare with \ucref{1st} and \ucref{2nd}.

\end{document}

这里\mylabel只保存字母和项目编号。格式在实际使用标签时决定。这是一种通用方法,可以延迟标签的格式化方式,因为它取决于上下文。

相关内容