在我的文档中,我列举了几个需要引用的项目。它们用简单的 (1)、(2)... 进行编号,但我还需要 (2')。为了更好地引用,我使用了enumitem
,但在更改一个标签时会失败:
\documentclass{article}
\usepackage{enumitem}
\begin{document}
\begin{enumerate}[label=\textnormal{(\arabic*)}]
\item text1\label{itm:1}.
\item text2\label{itm:2}.
\item[(2')] manually different label\label{itm:2b}.
\item text3\label{itm:3}.
\end{enumerate}
Referencing to \ref{itm:1}\ref{itm:2}\ref{itm:2b}\ref{itm:3}.
\end{document}
最后一行输出如下内容:
Referencing to (1)(2)(2)(3).
我该如何修复这个问题?
答案1
你可以像这样定义它:
\documentclass{article}
\usepackage{enumitem}
\makeatletter
\newcommand{\mylabel}[2]{#2\def\@currentlabel{#2}\label{#1}}
\makeatother
\begin{document}
\begin{enumerate}[label=\textnormal{(\arabic*)}]
\item text1\label{itm:1}.
\item text2\label{itm:2}.
\item[\mylabel{itm:2b}{(2')}] manually different label.
\item text3\label{itm:3}.
\end{enumerate}
Referencing to \ref{itm:1}\ref{itm:2}\ref{itm:2b}\ref{itm:3}.
\end{document}
答案2
这是一篇旧帖子,但所有现有的答案都定义了一些新命令,然后需要额外的调整才能使标签(2')
起作用。更好的方法是一次性“修复”标签,以便在以“正常”方式使用环境时引用能够按预期工作enumerate
:
\begin{enumerate}
\item text1\label{itm:1}.
\item text2\label{itm:2}.
\item[(2')] manually different label\label{itm:2b}.
\item text3\label{itm:3}.
\end{enumerate}
Referencing to \ref{itm:1}\ref{itm:2}\ref{itm:2b}\ref{itm:3}.
\@currentlabel
正如 Ambika Vanchinathano 所说,要做到这一点,我们需要重新定义每当给出可选参数时的值\item
。以下代码行定义了一个新的 item 命令,\myItem
它正是这样做的(我使用解析包,因为它提供了一种更清晰的方式来处理可选参数):
\let\realItem\item % save the original item command
\NewDocumentCommand\myItem{ o }{%
\IfNoValueTF{#1}%
{\realItem}% add an item
{\realItem[#1]\def\@currentlabel{#1}}% add an item and update label
}
也就是说,\myItem
使用原始\item
命令设置标签,并\@currentlabel
在给定可选参数时更新。实际上,我们需要将这些命令包装在里面,\makeatletter...\makeatother
但上面的代码基本上就是我们所需要的。
我们可以告诉枚举环境使用\myItem
而不是\item
使用\setlist
:
\setlist[enumerate]{before=\let\item\myItem}% make \item=\myItem
如果您使用超链接包裹。
把所有这些放在一起,下面是完整的代码。我已将 MWE 中的所有格式放入\setlist
命令中:
\documentclass{article}
\usepackage{xparse}
\let\realItem\item % save a copy of the original item
\makeatletter
\NewDocumentCommand\myItem{ o }{%
\IfNoValueTF{#1}%
{\realItem}% add an item
{\realItem[#1]\def\@currentlabel{#1}}% add an item and update label
}
\makeatother
\usepackage{enumitem}
\setlist[enumerate]{
before=\let\item\myItem, % use \myItem in enumerate
label=\textnormal{(\arabic*)}, % format the label
widest=(2') % set the widest label
}
\begin{document}
\begin{enumerate}
\item text1\label{itm:1}.
\item text2\label{itm:2}.
\item[(2')] manually different label\label{itm:2b}.
\item text3\label{itm:3}.
\end{enumerate}
Referencing to \ref{itm:1}\ref{itm:2}\ref{itm:2b}\ref{itm:3}.
\end{document}
这将产生预期的输出:
实际上,enumerate
您可能不想重新定义环境来像这样工作,而是希望使用以下命令创建一个新的enumerate
环境:\newlist
枚举项包裹。
实际上,我有点惊讶,当有一个可选参数时,枚举环境不会\@currentlabel
像这样重新定义......\item
答案3
如果使用hyperref
,最简单的方法是打印素数和有一个指向正确项目的链接是通过Ambika Vanchinathan
添加虚拟计数器(即\newcounter{dummy}
在序言中和\refstepcounter{dummy}
的定义中添加\mylabel
)稍微修改解决方案。
然而,我个人宁愿通过以下方式重新定义\item
(而不是\label
):
\makeatletter
\newcommand\myitem[1][]{\item[#1]\refstepcounter{dummy}\def\@currentlabel{#1}}
\makeatother
根据此定义,手动标记的物品应被引入为
\myitem[(2')]\label{itm:2b}
也就是说,相对于通常的引入事物的方式,变化很小,因此新定义更容易记住。我还会通过以下方式定义数学模式素数
\newcommand*{\mprime}{\ensuremath{'}}
完成 MWE:
\documentclass{article}
\newcounter{dummy}
\usepackage{hyperref}
\usepackage{enumitem}
\makeatletter
\newcommand\myitem[1][]{\item[#1]\refstepcounter{dummy}\def\@currentlabel{#1}}
\makeatother
\newcommand*{\mprime}{\ensuremath{'}}
\begin{document}
\begin{enumerate}[label=\textnormal{(\arabic*)}]
\item text1\label{itm:1}.
\item text2\label{itm:2}.
\myitem[(2\mprime)]\label{itm:2b} manually different label.
\item text3\label{itm:3}.
\end{enumerate}
Referencing to \ref{itm:1}\ref{itm:2}\ref{itm:2b}\ref{itm:3}.
\end{document}
答案4
您可以像这样动态地执行此操作,而不必自己输入“2”;只需传递后缀(例如'
)作为参数即可。此解决方案适用于有和没有hyperref
、cleveref
和的情况enumitem
,基本上依赖于新\labelsuffix
命令:
\documentclass{article}
\usepackage{xpatch}
\usepackage{hyperref}
\usepackage{cleveref}
\usepackage{enumitem}
% latex.ltx
% \def\item{
% - sets \@noitemargtrue if no argument
% - calls \@item
% \def\@item[#1]{
% - checks \if@noitemarg
% - calls \refstepcounter only if true
% ==> \item[] does not call \refstepcounter
% \def\refstepcounter#1{\stepcounter{#1}
% - defines \@currentlabel
% \def\label#1{\@bsphack
% - uses \@currentlabel
% ==> need to set \@currentlabel manually before calling label
% cleveref.sty
% \item looks unchanged (no mention)
% \refstepcounter is changed!
% \def\refstepcounter{%
% - calls \refstepcounter@optarg or \refstepcounter@noarg
% - basically the same flow, both call the old \refstepcounter
% - same problem: call to \refstepcounter was skipped;
% we have set \@currentlabel manually, and need to do similarly for \cref@currentlabel
\makeatletter
\newcommand{\labelsuffix}[2]{%
% this is required for hyperref:
\addtocounter{\@listctr}{-1}%
\refstepcounter{\@listctr}%
% fix for \ref:
\edef\@currentlabel{\@currentlabel#2}%
% fix for \cref (if you need to, load hyperref *before* cleveref):
% TODO: this ignores prefixes and counter aliases!
% TODO: to fix, copy/patch additional parts from \refstepcounter@noarg (from cleveref.sty)
\global\def\cref@currentlabel{[\@listctr][\arabic{\@listctr}][]\@currentlabel}%
% fix without enumitem
\expandafter\edef\csname the\@listctr\endcsname{\csname the\@listctr\endcsname#2}%
% fix with enumitem: label\@listctr does not contain the\@listctr, but c@\@listctr directly.
% so we patch; silently fails when enumitem is not loaded.
% https://tex.stackexchange.com/questions/340620/
\expandafter\def\expandafter\label@listctr\expandafter{\csname label\@listctr\endcsname}%
\expandafter\def\expandafter\c@@listctr\expandafter{\csname c@\@listctr\endcsname}%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter%
\xpatchcmd\expandafter\expandafter\expandafter%
\label@listctr\expandafter\expandafter\expandafter%
{\expandafter\expandafter\expandafter%
{\expandafter%
\c@@listctr\expandafter%
}\expandafter%
}\expandafter%
{\expandafter%
{\c@@listctr}#2%
}{}{err}%
\csname label\@listctr\endcsname%
\label{#1}%
}
\makeatother
\begin{document}
\begin{enumerate}
\item\label{item:A}
\item\label{item:Aa}
\begin{enumerate}
\item\label{item:B}
\item[\labelsuffix{item:C}{'}]
\item[\labelsuffix{item:D}{*}]
\item\label{item:E}
\end{enumerate}
\item[\labelsuffix{item:F}{'}]
\item\label{item:G}
\item[\labelsuffix{item:H}{*}]
\end{enumerate}
items \ref{item:A}, \ref{item:Aa}, \ref{item:B}, \ref{item:C}, \ref{item:D}, \ref{item:E}, \ref{item:F}, \ref{item:G} and \ref{item:H}
\cref{item:A,,item:Aa,,item:B,,item:C,,item:D,,item:E,,item:F,,item:G,,item:H}
(cref does not sort items in different levels correctly -- I have filed that as a bug with the developer.)
\end{document}