
Ich möchte dynamisch einige Makros definieren, die im Wesentlichen eine Liste von \ref
s erstellen. Ich kann diese Makros anscheinend definieren, aber dann kann ich sie nicht drucken.
Hier ist mein M(nicht)WIR:
\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}
Ich möchte, dass das \Assigned{}
Makro die dieser Person „zugewiesenen“ Artikelnummern ausgibt. Das heißt, nach der itemise
obigen Umgebung sollte ich nur Folgendes erhalten:
fred: 1,3
julie: 2,4,5
Leider fehlen mir die Artikelnummern und es erscheint nur:
fred:
julie:
Die M(non)WE-Latex-Dateien funktionieren problemlos, aber aus Gründen, die ich nicht verstehe, \Assigned
werden die Makros nicht erweitert. Ich habe viele Variationen mit \expandafter
1 oder mehr Malen ausprobiert, \edef
, ... aber nichts scheint zu funktionieren.
In der Protokolldatei \typeout{}
erzeugen die obigen Aufrufe Folgendes:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: `\DP@fred`
ASSIGNED: `\DP@julie`
Es sieht also so aus, als ob die \DP@#1
's von Bing richtig erstellt werden und die \Assigned{}
Makros nicht funktionieren, was wahrscheinlich ein Erweiterungsproblem ist. Die Verwendung \edef
funktioniert nicht ... aber die Tatsache, dass das Erweiterungsproblem INNERHALB von auftritt, lässt \typeout
mich vermuten, dass ich etwas Grundlegenderes falsch mache.
Kann mir jemand sagen, wie ich das beheben kann?
Als nächstes steht auf meiner Wunschliste, dass beispielsweise „1,3-6,8“ statt „1,3,4,5,6,8“ gedruckt wird. Aber der Reihe nach!
Antwort1
Die Umgebung enumerate
fügt eine Gruppe hinzu, daher sind die Änderungen \DP@#1
lokal und gehen nach dem Schließen der Umgebung verloren. Daher macht das Beispiel die Definition global:
\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}
Ergebnis:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: 1,3
ASSIGNED: 2,4,5
Update zur Bereichskomprimierung
Das Beispiel analysiert die Kommaliste \DP@#1
und definiert \Assign#1
mit komprimierten Bereichen aufeinanderfolgende Einträge:
\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}
Ergebnis:
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
Antwort2
Die Syntax \def\Assigned#1{}
ist falsch. Die richtige Vorgehensweise ist \expandafter\def\csname Assigned#1\endcsname{}
. Dadurch kann Ihr Code kompiliert werden. Außerdem \edef
ist das lokalisiert und kann nicht auf einer höheren Ebene aufgerufen werden. Eine Änderung in behebt \xdef
das Problem.
\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}
Die Protokolldatei enthält:
ASSIGN: 1
ASSIGN: 2
ASSIGN: 1,3
ASSIGN: 2,4
ASSIGN: 2,4,5
ASSIGNED: 1,3
ASSIGNED: 2,4,5
Antwort3
\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}
Antwort auf aktualisierte Frage
So erhalten Sie die Namen sowie die Artikelnummern:
\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}
Antwort4
Möglicherweise würden Sie eine LaTeX3-Version zu schätzen wissen.
\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}