PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit variablen Zählernamen und \AtEndDocument



Babba_Blubb
30-06-2012, 18:59
Nabend zusammen,

nachdem ich fast den ganzen Tag mit meinem ehr bescheidenen LaTeX-Wissen das Internet erfolglos nach einer Lösung für mein Problem durchsucht habe und nichts finden konnte hoffe ich, dass mir hier weitergeholfen werden kann.

Das Problem lässt sich etwas blöd beschreiben. Ich hab mich bemüht ein einfaches Beispiel zusammenzustellen, welches zwar für sich alleine nicht besonders sinnig ist, aber den Kern meines Problems darstellt. Der Kern ist, dass ich innerhalb des Dokumentes an verschiedenen stellen neue Zähler mit variablem Namen erstelle und den Wert dieser Zähler am Ende des Dokumentes über ein \AtEndDocument ausgebe. Hier mal der Quelltext:



\documentclass{article}
\begin{document}
\newcounter{printingCounterNumber}
\newcommand{\newPrintingCounter}{
\stepcounter{printingCounterNumber}

\newcounter{ctr\arabic{printingCounterNumber}}
\setcounter{ctr\arabic{printingCounterNumber}}{\va lue{printingCounterNumber}}

ctr\arabic{printingCounterNumber}: \arabic{ctr\arabic{printingCounterNumber}}\par
\AtEndDocument{
ctr\arabic{printingCounterNumber}: \arabic{ctr\arabic{printingCounterNumber}}\par
}
}

\newPrintingCounter
\newPrintingCounter
\newPrintingCounter
\end{document}


Das Kommando \newPrintingCounter dient der Erzeugung eines neuen Zählers. Damit sich die Namen dieser Zähler nicht überschneiden habe ich einen weiteren Zähler (printingCounterNumber), dessen Wert ich immer eins hochzähle und dann als Zahl mit in den Namen des neuen Zählers verbaue. Das funktioniert soweit auch ganz gut. Ich weise im obigen Beispiel dem Zähler ctr1 den Wert 1 zu, dem Zähler ctr2 den Wert 2 und so weiter. Wenn ich den Wert des neuen Zählers dann direkt ausgebe (also die Zeile vor \AtEndDocument), dann wird auch alles richtig ausgegeben.

Jetzt will ich den Wert des neu erzeugten Zählers aber auch am Ende des Dokumentes ausgeben. Dazu hab ich mir gedacht, mach ich ein \AtEndDocument und verwende zur Ausgabe die gleiche Zeile wie über dem \AtEndDocument. Hätte jetzt gedacht, dass dann am Ende die gleiche Ausgabe kommt. Allerdings kommt am Ende drei mal ein "crt3: 3".

Also erwartet hätte ich die Ausgabe
crt1: 1 ctr2: 2 crt3: 3
crt1: 1 ctr2: 2 crt3: 3

raus kommt allerdings
crt1: 1 ctr2: 2 crt3: 3
crt3: 3 ctr3: 3 crt3: 3

Hat jemand eine Idee wie ich es schaffen kann, dass über \AtEndDocument der Wert der drei unterschiedlichen Zähler ausgegeben wird und nicht drei mal der Wert des dritten Zählers? Wäre echt super, ich bin hier am Verzweifeln.

klops
30-06-2012, 19:56
\AtEndDocument expandiert nicht selbst, sondern der Code wird tatsächlich erst bei Verwendung expandiert. Also musst Du selbst für die Expansion sorgen:

\documentclass{article}
\begin{document}
\newcounter{printingCounterNumber}
\makeatletter
\newcommand*{\showthecounter}[1]{%
ctr#1: \@nameuse{thectr#1}%
}
\newcommand{\newPrintingCounter}{%
\stepcounter{printingCounterNumber}%
% Leerzeilen sind Absätze!!!
\newcounter{ctr\arabic{printingCounterNumber}}%
\setcounter{ctr\arabic{printingCounterNumber}}{\va lue{printingCounterNumber}}%
% Leerzeilen sind Absätze!
\showthecounter{\theprintingCounterNumber}\par
\edef\reserved@a{%
\noexpand\AtEndDocument{%
\noexpand\showthecounter{\theprintingCounterNumber }\noexpand\par}%
}\reserved@a
}

\newPrintingCounter
\newPrintingCounter
\newPrintingCounter
\end{document}

Babba_Blubb
30-06-2012, 20:33
Ahhhhhh, okay, ich verstehe (glaub ich zumindest).
Vielen vielen Dank für den Hinweis. Jetzt muss es nur noch schaffen, das auf meine richtige, größere Problemstellung zu übertragen.

Dazu mal noch ne Frage: Ist es auch möglich, dass ich ein Argument an ein Kommando direkt bei der Übergabe expandieren lasse? Wenn ja, dann könnte ich das ganze vielleicht in zwei Kommandos aufteilen, die dann so aussehen könnten:



\newcommand{doCreateTheCounter}[1]{
\newcounter{1}
\AtEndDocument{
#1: \arabic{#1}
}
}

\newcounter{printingCounterNumber}
\newcommand{\newPrintingCounter}{%
\stepcounter{printingCounterNumber}
\doCreateTheCounter{\irgendEinKommandoDasSeinArgum entZuEinerZeichenketteAuswertet{ctr\arabic{printin gCounterNumber}}}
}


Sowas würde sich mit meinem LaTeX-Kenntnissen besser vereinen lassen ;)

Viele Grüße, danke nochmal und schönen Abend noch

klops
02-07-2012, 07:49
So wird das nicht funktionieren. Man kann sich natürlich ein \usewithexandedarg definieren:


\newcommand*{\usewithexpandedarg}[2]{%
\protected@edef\reserved@a{\noexpand#1{#2}}\reserv ed@a
}

und dann den Aufruf in
\usewithexpandedarg\doCreateTheCounter{ctr\theprin tingCounterNumber} ändern. Ob Dir das hilft, hängt auch davon ab, was Du konkret machen willst.

Eventuell wäre sogar eine Lösung mit \expandafter möglich. Das hängt von der konkreten Anwendung ab.

BTW: Zum Unterschied zwischen \edef und \protected@edef siehe source2e.pdf. Für deine gezeigte Anwendung kann man auch \edef verwenden. Für eine allgemeine Definition wie oben würde ich eher zu \protected@edef raten. Außerdem würde ich empfehlen mit \the<Zählername> zu arbeiten, wie ich das bereits im vorherigen Beispiel gezeigt habe. Zusätzlich sei darauf hingewiesen, dass die Zahl der Zähler normalerweise begrenzt ist. Es empfiehlt sich deshalb eventuell das Paket etex zu verwenden. Für Befehle mit zwei Argumenten bietet der LaTeX-Kern (siehe source2e.pdf) die Anweisung \expandtwoargs ähnlich zu obiger Anweisung für Befehle mit einem Argument. Dabei wird \edef statt \protected@edef verwendet.

Babba_Blubb
03-07-2012, 17:10
ok, vielen tausend Dank nochmal für deine Hilfestellungen! Ich hatte es am Sonntag mit deinem ersten Lösungsvorschlag versucht und der hat dann auch direkt mit meiner eigentlichen Problemstellung funktioniert.

Falls dich die eigentliche Problemstellung interessiert: Ich benutze das Paket totcount mit dem man Zähler definieren kann, deren Werte nach dem Bauen in der aux-Datei abgelegt werden und dann beim erneuten Bauen direkt von Anfang an zur Verfügung stehen. Die Werte dieser Zähler werden in einem \AtEndDocument in die aux-Datei geschrieben und wenn man jetzt Zähler mit variablen Namen wie aus meinem Beispiel verwendet, dann wird für jeden gespeicherten Zähler der letzte variable Name verwendet. Da stand ich halt gut auf dem Schlauch. Jetzt wo ich allerdings weiß, dass diese \AtEndDocument erst ganz am Schluss zur Auswertung kommen, wird mir die Sache klar und mit dem von dir beschriebenen Lösungsansatz läuft es jetzt wie geschmiert.

Danke nochmal!