\ pgfmathsetlengthmacro nicht kompatibel mit einer Schleife?

Sep 06 2020

Der folgende Code wird perfekt kompiliert:

\documentclass[]{article}

\usepackage[most]{tcolorbox}

\newcommand\UseImageLeft[1]{%
\IfFileExists{#1\i.jpg}%
  {\includegraphics[scale=0.2]{#1\i.jpg}}%
    {\includegraphics[scale=0.2]{example-image.jpg}}%
}

\def\ImageLeft{\UseImageLeft{Image-}}

% Problem ===================================
% \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================

\begin{document}

\foreach \i in {1,...,2}{

% On any page (begin)
\begin{tcolorbox}[]
\begin{tcbitemize}[]
\tcbitem[] \ImageLeft
\end{tcbitemize}
\end{tcolorbox}
% On any page (end)

\newpage
}

\end{document}

Mein Problem ist, dass ich auskommentieren möchte \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}, aber dann wird der Code nicht mehr kompiliert. Wie kann ich das bitte beheben?

Antworten

2 UlrichDiez Sep 06 2020 at 14:31

Problem 1:

Sie verwenden \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")} außerhalb der \foreachSchleife. Aber mit \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}dem Makro \ImageLeftwas wiederum Anwendungen verwendet , \UseImageLeftdie wiederum Anwendungen \iwährend \idefiniert die Anzahl eines Bildes liefern nur innerhalb der \foreach-loop.

Problem 2:

Sie haben, \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}was von Muster ist

\pgfmathsetlengthmacro\LeftWidth{⟨expression⟩}
mit
⟨expression⟩ = width("\ImageLeft")
, während
width("\ImageLeft")
wiederum Muster mit = ist .
width(⟨expression⟩)

⟨expression⟩"\ImageLeft"

Dies bedeutet, dass \ImageLeftals Teil eines ⟨expression⟩zweimal ausgewertet wird :

Das erste Mal, wenn die ⟨expression⟩Bildung des Arguments von \pgfmathsetlengthmacro\LeftWidthausgewertet wird.

Das zweite Mal, wenn die ⟨expression⟩Bildung des Arguments von width(...)ausgewertet wird.

pgfmanual.pdf, Abschnitt "95.2 Syntax für mathematische Ausdrücke: Operatoren" sagt in der Erklärung des Operators:"x"

... Da jedoch jeder Ausdruck vor dem Parsen mit \ edef erweitert wird, müssen Makros (z. B. Schriftbefehle wie \ tt oder \ Huge) möglicherweise vor dieser Erweiterung "geschützt" werden (z. B. \ noexpand \ Huge). Idealerweise sollten Sie solche Makros trotzdem vermeiden. Offensichtlich sollten diese Operatoren mit großer Sorgfalt verwendet werden, da weitere Berechnungen mit dem Ergebnis wahrscheinlich nicht möglich sind.

Diese Informationen beziehen sich nicht nur auf den -operator. Diese Informationen sind relevant für die Bewertung eines . Es ist eine allgemeine Regel, die bei der Bewertung von jedem angewendet wird . Daher halte ich es nicht für eine gute Idee, diese Informationen nur zu vermitteln, während ein spezieller Operator erklärt wird."x"⟨expression⟩⟨expression⟩

Sei es wie es mag:

Wenn Sie die Informationen zusammenfügen, werden Sie feststellen, dass sie zweimal \ImageLeftausgewertet werden \edef. Da die Expansionskette \ImageLeft→ \UseImageLeft→ ist ...\includegraphics..., bedeutet dies, dass zweimal Versuche zur Bewertung \includegraphicsüber \edefstattfinden.
Falls Sie jedoch nicht die eine der neuesten TeX-Distributionen verwenden, \includegraphicsfunktioniert dies nicht in \edefExpansionskontexten. Dies liegt daran, dass in älteren TeX-Distributionen \includegraphicsnicht "geschützt" ist - "geschützt" bezieht sich auf einen LaTeX-internen Mechanismus zum Verhindern der Erweiterung von Befehlen in Situationen, in denen diese Erweiterung nicht funktionieren würde - und "hängt davon ab", temporäre Zuweisungen durchzuführen, z. in Bezug auf \def, während solche Aufträge nicht ausgeführt werden, während \edef-evaluation im Gange ist. \edefLöst die Erweiterung erweiterbarer Token aus, während \defes sich um ein nicht erweiterbares Grundelement handelt.

Wenn Sie also keine der neuesten TeX-Distributionen verwenden, müssen Sie Vorsichtsmaßnahmen treffen, um zu verhindern, dass der Befehl bei jeder dieser \ImageLeftBewertungen erweitert / ausgewertet wird (und somit auch die Erweiterung / Auswertung verhindert wird \includegraphics) \edef. (Bei den neuesten TeX-Distributionen sind diese Vorsichtsmaßnahmen weder störend noch erforderlich.)

Sie können die Erweiterung / Auswertung verhindern, indem Sie ein Präfix \ImageLeftmit voranstellen \noexpand\noexpand\noexpand.

Die erste \edefBewertung, angewendet auf <code>\noexpand\noexpand\noexpand\ImageLeft</code>,
ergibt Renditen
<code>\noexpand\ImageLeft</code>.
Die zweite \edefBewertung wird auf das angewendet, was wiederum ergibt :
<code>\ImageLeft</code>.

Problem 3:

egreg wies darauf hin, dass dies \ibereits in LaTeX definiert ist und dass Sie diese Definition wahrscheinlich nicht überschreiben möchten. Deshalb habe ich im folgenden Beispiel \NiceForEachElementstatt verwendet \i.

\documentclass[]{article}

\usepackage[most]{tcolorbox}

\newcommand\UseImageLeft[1]{%
\IfFileExists{#1\NiceForEachElement.jpg}%
  {\includegraphics[scale=0.2]{#1\NiceForEachElement.jpg}}%
    {\includegraphics[scale=0.2]{example-image.jpg}}%
}

\def\ImageLeft{\UseImageLeft{Image-}}

% Problem ===================================
%\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================

\begin{document}

\foreach \NiceForEachElement in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth
% On any page (begin)
\begin{tcolorbox}[]%
\begin{tcbitemize}[]%
\tcbitem[] \ImageLeft
\end{tcbitemize}%
\end{tcolorbox}%
% On any page (end)
\newpage
}

\end{document}

Wenn Sie auch \ImageLeftaußerhalb der Schleife verwenden möchten , definieren Sie \ImageLeftetc, um ein Argument zu verarbeiten, anstatt \i/ zu verarbeiten \NiceForEachElement.
Innerhalb der Schleife können Sie \i/ \NiceForEachElementals Argument übergeben.
Außerhalb der Schleife können Sie die Nummer des Bildes direkt als Argument übergeben.

\documentclass[]{article}

\usepackage[most]{tcolorbox}

% Define the command \NiceForEachElement to ensure error-message in case it is already defined.
% This way you can ensure to a certain degree that using `\niceelement` as Foreach-variable
% does not override something that alerady exists.
\newcommand\NiceForEachElement{}%

\newcommand\UseImageLeft[2]{%
% #1 preceding phrase "image-"
% #2 number of image
\IfFileExists{#1#2.jpg}%
  {\includegraphics[scale=0.2]{#1#2.jpg}}%
    {\includegraphics[scale=0.2]{example-image.jpg}}%
}

\newcommand*\ImageLeft[1]{\UseImageLeft{Image-}{#1}}

% Problem ===================================
%\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================

\begin{document}

% outside the loop the width of Image-7.jpg or example-image.jpg:

\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{7}")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth

% inside the loop:

\foreach \NiceForEachElement in {1,...,2}{%
  \pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{\NiceForEachElement}")}%
  %Activate the following line in case you wish to see on screen/console  what the definition of \LeftWidth looks like now:
  %\show\LeftWidth
  % On any page (begin)
  \begin{tcolorbox}[]%
  \begin{tcbitemize}[]%
  \tcbitem[] \ImageLeft{\NiceForEachElement}%
  \end{tcbitemize}%
  \end{tcolorbox}%
  % On any page (end)
  \newpage
}

\end{document}
2 UlrikeFischer Sep 06 2020 at 13:59

Verwenden Sie keine Schleifenvariablen außerhalb einer Schleife, weder in ausgeführtem Code noch in Definitionen.

\documentclass[]{article}

\usepackage[most]{tcolorbox}

\newcommand\UseImageLeft[1]{%
\IfFileExists{#1.jpg}%
  {\includegraphics[scale=0.2]{#1.jpg}}%
  {\includegraphics[scale=0.2]{example-image.jpg}}%
}


\begin{document}

\foreach \i in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\UseImageLeft{image\i}")}%
% On any page (begin)
\begin{tcolorbox}[]
\begin{tcbitemize}[]
\tcbitem[] \UseImageLeft{image\i}
\end{tcbitemize}
\end{tcolorbox}
% On any page (end)

\newpage
}^

\end{document}