Antwort auf aktualisierte Frage

Antwort auf aktualisierte Frage

Ich möchte dynamisch einige Makros definieren, die im Wesentlichen eine Liste von \refs 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 itemiseobigen 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, \Assignedwerden die Makros nicht erweitert. Ich habe viele Variationen mit \expandafter1 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 \edeffunktioniert nicht ... aber die Tatsache, dass das Erweiterungsproblem INNERHALB von auftritt, lässt \typeoutmich 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 enumeratefügt eine Gruppe hinzu, daher sind die Änderungen \DP@#1lokal 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@#1und definiert \Assign#1mit 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 \edefist das lokalisiert und kann nicht auf einer höheren Ebene aufgerufen werden. Eine Änderung in behebt \xdefdas 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}

Zuordnungen

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}

Aufgaben nach Namen

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}

verwandte Informationen