我想动态定义一些宏,这些宏本质上是创建一个\ref
s 列表。我似乎能够定义这些宏,但无法打印它们。
这是我的 M(non)WE:
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname\def\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}
\else\def\DP@tmp{\@currentlabel}
\fi
\expandafter\edef\csname DP@#1\endcsname{\DP@tmp}
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{#1: \csname DP@#1\endcsname}
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
我希望\Assigned{}
宏打印出“分配”给该人的项目编号。也就是说,在itemise
上述环境之后,我应该得到:
fred: 1,3
julie: 2,4,5
不幸的是,我缺少产品编号,我只得到:
fred:
julie:
M(non)WE latex 没有任何问题,但出于我不明白的原因,\Assigned
宏没有扩展。我尝试过使用\expandafter
1 次或多次的多种变体,\edef
……但似乎没有任何效果。
在日志文件中,\typeout{}
上面的调用产生了:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: `\DP@fred`
ASSIGNED: `\DP@julie`
因此看起来, 的\DP@#1
创建是正确的,而宏\Assigned{}
不起作用,这可能是一个扩展问题。使用\edef
不起作用……但扩展问题发生在 内部,这一事实表明\typeout
我做了一些更根本的错误。
谁能告诉我如何解决这个问题?
我的下一个愿望是让它打印“1,3-6,8”,而不是“1,3,4,5,6,8”。但首先要做的是!
答案1
环境enumerate
添加了一个组,因此对的更改\DP@#1
是本地的,在环境关闭后会丢失。因此,该示例使定义成为全局的:
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname
\edef\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}%
\else
\edef\DP@tmp{\@currentlabel}%
\fi
\global\expandafter\let\csname DP@#1\endcsname\DP@tmp
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{%
% \expandafter\def\csname Assigned#1\endcsname{\csname DP@#1\endcsname}
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
结果:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: 1,3
ASSIGNED: 2,4,5
范围压缩更新
该示例解析逗号列表\DP@#1
并定义\Assign#1
连续条目的压缩范围:
\documentclass{article}
\usepackage{kvoptions}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname
\edef\DPx@tmp{\csname DP@#1\endcsname,\@currentlabel}%
\else
\edef\DPx@tmp{\@currentlabel}%
\fi
\global\expandafter\let\csname DP@#1\endcsname\DPx@tmp
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{%
\begingroup
\let\DPx@curr\@empty
\let\DPx@tmp\@empty
\expandafter\expandafter\expandafter\comma@parse
\expandafter\expandafter\expandafter{\csname DP@#1\endcsname}%
\AssignedAux
\ifx\DPx@curr\@empty
\else
\edef\DPx@tmp{\DPx@tmp-\DPx@curr}%
\fi
\global\expandafter\let\csname Assigned#1\endcsname\DPx@tmp
\endgroup
\typeout{ASSIGNED: \csname Assigned#1\endcsname}
}
\def\AssignedAux#1{%
\ifx\DPx@tmp\@empty
\def\DPx@tmp{#1}%
\count@=#1\relax
\else
\advance\count@\@ne
\ifnum#1=\count@
\def\DPx@curr{#1}%
\else
\count@=#1\relax
\ifx\DPx@curr\@empty
\edef\DPx@tmp{\DPx@tmp,#1}%
\else
\edef\DPx@tmp{\DPx@tmp-\DPx@curr,#1}%
\let\DPx@curr\@empty
\fi
\fi
\fi
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}\Assign{fred}
\item Strawberries \Assign{julie}
\item Pears \Assign{julie}
\item Lemons \Assign{fred}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
结果:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 1,3,4
ASSIGN: 2,4,5
ASSIGN: 2,4,5,6
ASSIGN: 1,3,4,7
ASSIGNED: 1,3-4,7
ASSIGNED: 2,4-6
答案2
语法\def\Assigned#1{}
不正确。正确的方法是\expandafter\def\csname Assigned#1\endcsname{}
。这样您的代码就可以编译了。此外,\edef
是本地化的,无法在更高级别访问。将其更改为 可以\xdef
解决这个问题。
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname\def\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}
\else\def\DP@tmp{\@currentlabel}
\fi
\expandafter\xdef\csname DP@#1\endcsname{\DP@tmp}
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{\expandafter\def\csname Assigned#1\endcsname{\csname DP@#1\endcsname}
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
日志文件包含:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: 1,3
ASSIGNED: 2,4,5
答案3
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname\def\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}
\else\def\DP@tmp{\@currentlabel}
\fi
\expandafter\xdef\csname DP@#1\endcsname{\DP@tmp}
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{%
\csname DP@#1\endcsname
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
对更新后问题的回复
要获取名称以及产品编号:
\documentclass{article}
\makeatletter
\def\Assign#1{% if \DP@#1 is defined append to it otherwise create it
\ifcsname DP@#1\endcsname\def\DP@tmp{\csname DP@#1\endcsname,\@currentlabel}
\else\def\DP@tmp{\@currentlabel}
\fi
\expandafter\xdef\csname DP@#1\endcsname{\DP@tmp}
\typeout{ASSIGN: \csname DP@#1\endcsname}
}
\def\Assigned#1{%
#1: \csname DP@#1\endcsname
\typeout{ASSIGNED: \csname DP@#1\endcsname}
}
\makeatother
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
\Assigned{fred} % should print 1,3
\Assigned{julie} % should print 2,4,5
\end{document}
答案4
您可能会喜欢 LaTeX3 版本;
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\Assign}{m}
{
\andrew_assign:n { #1 }
}
\NewDocumentCommand{\Assigned}{m}
{
\andrew_assigned:n { #2 }
}
% syntactic sugar for shortening code
\cs_new:Npn \__andrew_seq:n #1
{
g_andrew_assignee_#1_seq
}
\cs_new_protected:Npn \andrew_assign:n #1
{% if the assignee is not yet defined, create a sequence
\seq_if_exist:cF { \__andrew_seq:n { #1 } }
{
\seq_new:c { \__andrew_seq:n { #1 } }
}
% globally add the item to the assignee's sequence
\seq_gput_right:cv { \__andrew_seq:n { #1 } } { @currentlabel }
}
\cs_new:Npn \andrew_assigned:n #1
{% print the assignee's items separated by a comma
\seq_use:cn { \__andrew_seq:n { #1 } } { ,~ }
}
\cs_generate_variant:Nn \seq_gput_right:Nn { cv }
\cs_generate_variant:Nn \seq_use:Nn { c }
\ExplSyntaxOff
\begin{document}
\begin{enumerate}
\item Apples \Assign{fred}
\item Oranges \Assign{julie}
\item Bananas \Assign{fred}
\item Mangos \Assign{julie}
\item Strawberries \Assign{julie}
\end{enumerate}
Fred has \Assigned{fred} % should print 1,3
Julie has \Assigned{julie} % should print 2,4,5
\end{document}