\ pgfmathsetlengthmacro несовместим с циклом?
Следующий код компилируется отлично:
\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}
Моя проблема в том, что я хочу раскомментировать \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}, но тогда код больше не компилируется. Как я могу это исправить?
Ответы
Проблема 1:
Вы можете использовать \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")} вне в \foreach-loop. Но с \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}макро \ImageLeftиспользуется , который , в свою очередь , использует \UseImageLeftкоторый , в свою очередь , использует в \iто время как \iопределен , чтобы получить количество изображений только в пределах от \foreach-loop.
Проблема 2:
У вас \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}есть образец
\pgfmathsetlengthmacro\LeftWidth{⟨expression⟩}
с
⟨expression⟩ = width("\ImageLeft")
, а
width("\ImageLeft")
в свою очередь имеет образец
с = .
width(⟨expression⟩)
⟨expression⟩"\ImageLeft"
Это означает, что \ImageLeftон оценивается как часть ⟨expression⟩дважды:
Первый раз, когда оценивается ⟨expression⟩формирующий аргумент \pgfmathsetlengthmacro\LeftWidth.
Второй раз, когда оценивается ⟨expression⟩формирующий аргумент width(...).
pgfmanual.pdf, раздел «95.2 Синтаксис математических выражений: операторы», в объяснении оператора -оператора:"x"
... Однако, поскольку каждое выражение перед анализом раскрывается с помощью \ edef, макросы (например, команды шрифтов, такие как \ tt или \ Huge) могут нуждаться в «защите» от этого раскрытия (например, \ noexpand \ Huge). В идеале вам все равно следует избегать таких макросов. Очевидно, что эти операторы следует использовать с большой осторожностью, поскольку дальнейшие вычисления маловероятны с полученным результатом.
Эта информация не относится только к оператору. Эта информация актуальна всякий раз, когда дело доходит до оценки . Это общее правило, которое применяется при оценке каждого . Поэтому я думаю, что передавать эту информацию только при объяснении специального оператора - не лучшая идея."x"⟨expression⟩⟨expression⟩
Как бы то ни было:
Собирая информацию вместе, вы обнаруживаете, что \ImageLeftона оценивается \edefдважды. Поскольку цепочка раскрытия \ImageLeft→ \UseImageLeft→ ...\includegraphics..., это означает, что имеют место две попытки вычисления \includegraphicsvia \edef.
Но в случае, если вы не используете один из самых последних TeX-дистрибутивов, \includegraphicsэто не работает в \edef-expansion-контекстах. Это связано с тем, что в старых TeX-дистрибутивах \includegraphicsне «защищен» - «защищен» относится к внутреннему механизму LaTeX для предотвращения расширения команд в ситуациях, когда это расширение не сработает - и «полагается на» выполнение временных назначений, например, с точки зрения \def, пока такие задания не выполняются, пока \edefидет оценка. \edefзапускает расширение расширяемых токенов, пока \defявляется нерасширяемым примитивом.
Поэтому, если вы не используете один из самых последних TeX-дистрибутивов, вам необходимо принять меры предосторожности для предотвращения расширения / оценки команды \ImageLeft(и, таким образом, предотвращения расширения / оценки \includegraphics) с каждым из этих \edefоценок. (В самых последних дистрибутивах TeX эти меры предосторожности не доставляют неудобств и не требуются.)
Вы можете предотвратить расширение / оценка предваряя \ImageLeftс \noexpand\noexpand\noexpand.
Первая \edef-Оценка, наносит на <code>\noexpand\noexpand\noexpand\ImageLeft</code>,
урожайность
<code>\noexpand\ImageLeft</code>.
Вторая \edef-Оценка будет применяться на то, что , в свою очередь , урожайности:
<code>\ImageLeft</code>.
Проблема 3:
egreg указал, что \iэто уже определено в LaTeX и что вы, вероятно, не хотите отменять это определение. Поэтому в приведенном ниже примере я использовал \NiceForEachElementвместо \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}
Если вы хотите иметь возможность использовать и \ImageLeftвне цикла, определите \ImageLeftetc для обработки аргумента вместо обработки \i/ \NiceForEachElement.
Внутри цикла вы можете передать \i/ в \NiceForEachElementкачестве аргумента.
Вне цикла вы можете напрямую передать номер изображения в качестве аргумента.
\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}
Не используйте переменные цикла вне цикла, ни в исполняемом коде, ни в определениях.
\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}