我正在尝试将一些文本(使用计数器动态生成)关联到标签,以便我可以引用该标签并打印相关文本(无需重新生成它,这会导致计数器出现问题)。
使用示例:
\textLabel{key}{\dynamicText}
之后,在文档的某个地方,我想要一个新的宏,链接到键并显示由 \dynamictext 生成的文本。
这个宏不太起作用:
\makeatletter
\newcommand{\textLabel}[2]{%
\protected@edef\var{\expandafter\noexpand#2}%
\label{#1}\var%
\global\expandafter\def\csname#1\endcsname{\hyperref[#1]{\var}}%
}
\makeatother
宏\var
似乎工作正常。问题是,用 标识的宏\#1
在文档中不可见,并产生错误(未找到控制序列)。
我哪里做错了?
背景:我有一长串项目,需要以某种奇怪格式提供唯一 ID。我通过调用宏来自动生成列表中项目的 ID,该宏会增加一些计数器并根据计数器的值返回 ID。
现在,我想写入生成的 ID 并引用这些项目,而无需调用用于构建它们的宏。(这意味着以\getID
相同的顺序和次数调用,我不想这样做)
这是一个最小(不)工作的例子:
\documentclass[11pt]{report}
\makeatletter
\newcommand{\textLabel}[2]{%
\protected@edef\var{\expandafter\noexpand#2}%
\label{#1}\var%
\global\expandafter\def\csname #1\endcsname{\hyperref[#1]{\var}}
}
\makeatother
\newcounter{req}
\newcommand{\getid}[1]{%
\stepcounter{req}%
#1.\arabic{req}%
}
\begin{document}
\begin{itemize}
\item \textLabel{itemkeyone}{\getid{ITEM}}
\item \textLabel{itemkeytwo}{\getid{ITEM}}
\end{itemize}
\itemkeyone %I want: ITEM.1, instead produces command not found
\end{document}
这是一个最小的工作示例,但行为错误:
\documentclass[11pt]{report}
\usepackage{hyperref}
\newcommand{\textLabel}[2]{%
\label{#1}#2%
\global\expandafter\def\csname#1\endcsname{\hyperref[#1]{#2}}
}
\newcounter{req}
\newcommand{\getid}[1]{%
\stepcounter{req}%
#1.\arabic{req}%
}
\begin{document}
\begin{itemize}
\item \textLabel{itemkeyone}{\getid{ITEM}}
\item \textLabel{itemkeytwo}{\getid{ITEM}}
\end{itemize}
\itemkeyone %I want: ITEM.1, instead produces ITEM.3
\end{document}
非常感谢
答案1
这是一个完全不同的方法鍵盤。由于有这么多注释,代码比 Manuel 的要长,所以也许我不能声称它很简单,但我就是喜欢用 pgfkeys 来做这种事。
为了证明它的工作原理,下面是我的代码生成的结果: ...代码如下:
\documentclass{article}
\usepackage{etoolbox}
\usepackage{pgfkeys}
\pgfkeys{/MyLabels/.is family, /MyLabels,
% set labels using \pgfkeyssetvalue => can test with \pgfkeysifdefined
% This allows arbitrary new keys to be defined on the fly
.unknown/.code={\pgfkeyssetvalue{/MyLabels/\pgfkeyscurrentname}{#1}},
}
\newcounter{getID}% a dummy counter to imitate \getID
\newcommand\SetLabel[1]{% set label to current value of getID
\stepcounter{getID}% might want \refstepcounter in real life
Settting: #1 = ID\arabic{getID} %
\pgfkeys{/MyLabels,#1/.expanded=ID\arabic{getID}}% force expansion
(stored value: \pgfkeys{/MyLabels/#1}).
}
\newcommand\UseLabel[1]{% print label if it bas been defined
Getting: #1 =
\pgfkeysifdefined{/MyLabels/#1}%
{\pgfkeysvalueof{/MyLabels/#1}}% print if defined
{???}% question marks if not defined
.%
}
\begin{document}
\SetLabel{first}
\SetLabel{second}
\UseLabel{first}
\UseLabel{second}
\UseLabel{first}
\end{document}
编辑:解决方案 II
我意识到这都是小题大做:你应该只使用 LaTeX 的\label
和\ref
命令。当你创建标签时,会发生的情况是,当前的值\@currentlabel
被写入辅助文件,然后在下一次编译时可以使用访问\ref
。因此,如果你将\@currentlabel
输出设置为,\getID
那么你就完成了。但是,你不能将\@currentlabel
等于设置为,\getID{item}
因为\getID
命令包含一些不可扩展的内容。相反,你应该将\getID
设置设置为虚拟变量,或者更好的是,设置\@currentlabel
。
以下是根据您的 MWE 提出的第二个解决方案:
\documentclass[11pt]{report}
\newcommand\textLabel[2]{\getid{#2}\label{#1}}
\makeatletter
\newcounter{req}
\newcommand{\getid}[1]{%
\stepcounter{req}%
\def\@currentlabel{#1.\arabic{req}}%
}
\makeatother
\begin{document}
\begin{itemize}
\item \textLabel{itemkeyone}{ITEM}
\item \textLabel{itemkeytwo}{ITEM}
\end{itemize}
\ref{itemkeyone} %I want: ITEM.1
\ref{itemkeytwo} %I want: ITEM.1
\end{document}
由于这是在幕后使用,标签将从一次编译持续到下一次编译,但您需要对文档进行两次编译才能生效\label
。\ref
输出如下:
答案2
textlabels
一种将伪造的标签写入文件然后.aux
手动建立的风格。\hypertarget
\hyperlink
\documentclass[11pt]{report}
\usepackage{hyperref}
\newcounter{req}
\makeatletter
\newcommand{\textLabel}[2]{%
\stepcounter{req}%
\hypertarget{#1.\number\value{req}}{#2.\arabic{req}}%
\immediate\write\@auxout{%
\string\newlabel{#1.\number\value{req}}{{#2.\number\value{req}}{}{}{}{}} % Write the text label!
}
\expandafter\xdef\csname #1\endcsname{%
\unexpanded{\hyperlink}{#1.\number\value{req}}{\getrefnumber{#1.\number\value{req}}}
}
}
\makeatother
\begin{document}
\chapter{Foo} \label{foolabel}
\begin{itemize}
\item \textLabel{itemkeyone}{ITEM}
\clearpage
\item \textLabel{itemkeytwo}{ITEM}
\end{itemize}
\clearpage
\itemkeyone %I want: ITEM.1, instead produces ITEM.3
\itemkeytwo
\end{document}
答案3
我认为这是可行的,但还没有彻底测试过
\documentclass{scrartcl}
\usepackage{hyperref}
\newcounter{req}
\newcommand*\getid[1]{\def\thereq{#1.\arabic{req}}\refstepcounter{req}\thereq}
\begin{document}
\begin{itemize}
\item \getid{ITEM} \label{itemkeyone}
\item \getid{ITEM} \label{itemkeytwo}
\end{itemize}
\ref{itemkeyone}
\end{document}